diff options
author | tyler-ball <tyleraball@gmail.com> | 2014-09-25 17:36:09 -0700 |
---|---|---|
committer | tyler-ball <tyleraball@gmail.com> | 2014-10-08 09:07:48 -0700 |
commit | 52344098cae84d8e4e94066cd9408ec8a89e9a6b (patch) | |
tree | 654dc76100ae42d3d5f9c1aa8e55799cf7023416 | |
parent | a9d8b70e0944f5cb8c695bf14f1b71e68e9a3e36 (diff) | |
download | chef-52344098cae84d8e4e94066cd9408ec8a89e9a6b.tar.gz |
First pass at removing JSON dependency, switching it for ffi-yajl
74 files changed, 326 insertions, 176 deletions
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md index e509e38ce8..11183db7c1 100644 --- a/DOC_CHANGES.md +++ b/DOC_CHANGES.md @@ -252,3 +252,8 @@ Archive reskit EOH end ``` + +### Removed dependencies on the json gem, replaced with ffi-yajl +We should no longer require the 'json' gem for any JSON parsing, and should instead be using the Chef::JSONCompat +library everywhere. Consumers should not see any changes, unless they relied on the transitive 'json' gem dependency. +In this case, they should upgrade their code to take advantage of the Chef::JSONCompat library instead. diff --git a/chef.gemspec b/chef.gemspec index 7c53618a51..7e9dc257b2 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |s| # it's the version I had when I tested. s.add_dependency "mime-types", "~> 1.16" - s.add_dependency "ffi-yajl", "~> 1.0" + s.add_dependency "ffi-yajl", "~> 1.1" s.add_dependency "net-ssh", "~> 2.6" s.add_dependency "net-ssh-multi", "~> 1.1" # CHEF-3027: The knife-cloud plugins require newer features from highline, core chef should not. diff --git a/lib/chef/api_client.rb b/lib/chef/api_client.rb index 7b7fd99ff7..334fb23f38 100644 --- a/lib/chef/api_client.rb +++ b/lib/chef/api_client.rb @@ -121,7 +121,7 @@ class Chef # # @return [String] the JSON string. def to_json(*a) - to_hash.to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) end def self.json_create(o) diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb index b84fc1945d..a88bf0c256 100644 --- a/lib/chef/chef_fs/chef_fs_data_store.rb +++ b/lib/chef/chef_fs/chef_fs_data_store.rb @@ -23,6 +23,7 @@ require 'chef/chef_fs/file_pattern' require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/memory_root' +require 'chef/json_compat' require 'fileutils' class Chef @@ -114,7 +115,7 @@ class Chef end end end - JSON.pretty_generate(result) + Chef::JSONCompat.to_json_pretty(result) else begin @@ -269,7 +270,7 @@ class Chef # Create a little Chef::ChefFS memory filesystem with the data cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading') - cookbook = JSON.parse(data, :create_additions => false) + cookbook = Chef::JSONCompat.parse(data, :create_additions => false) cookbook.each_pair do |key, value| if value.is_a?(Array) value.each do |file| diff --git a/lib/chef/chef_fs/command_line.rb b/lib/chef/chef_fs/command_line.rb index 967c59ecae..5fa770089b 100644 --- a/lib/chef/chef_fs/command_line.rb +++ b/lib/chef/chef_fs/command_line.rb @@ -19,6 +19,7 @@ require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/chef_fs/file_system/operation_not_allowed_error' +require 'chef/json_compat' require 'chef/util/diff' class Chef @@ -251,9 +252,9 @@ class Chef end def self.canonicalize_json(json_text) - parsed_json = JSON.parse(json_text, :create_additions => false) + parsed_json = Chef::JSONCompat.parse(json_text, :create_additions => false) sorted_json = sort_keys(parsed_json) - JSON.pretty_generate(sorted_json) + Chef::JSONCompat.to_json_pretty(sorted_json) end def self.diff_text(old_path, new_path, old_value, new_value) diff --git a/lib/chef/chef_fs/file_system/acl_entry.rb b/lib/chef/chef_fs/file_system/acl_entry.rb index 8edc02d5c5..1659b557ba 100644 --- a/lib/chef/chef_fs/file_system/acl_entry.rb +++ b/lib/chef/chef_fs/file_system/acl_entry.rb @@ -20,6 +20,7 @@ require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/operation_not_allowed_error' require 'chef/chef_fs/file_system/operation_failed_error' +require 'chef/json_compat' class Chef module ChefFS @@ -37,7 +38,7 @@ class Chef def write(file_contents) # ACL writes are fun. - acls = data_handler.normalize(JSON.parse(file_contents, :create_additions => false), self) + acls = data_handler.normalize(Chef::JSONCompat.parse(file_contents, :create_additions => false), self) PERMISSIONS.each do |permission| begin rest.put("#{api_path}/#{permission}", { permission => acls[permission] }) diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb index 3d3f58201e..d22d11b0f3 100644 --- a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb @@ -19,6 +19,7 @@ require 'chef/chef_fs/file_system/file_system_entry' require 'chef/chef_fs/file_system/not_found_error' +require 'chef/json_compat' class Chef module ChefFS @@ -41,7 +42,7 @@ class Chef def chef_object begin - return data_handler.chef_object(JSON.parse(read, :create_additions => false)) + return data_handler.chef_object(Chef::JSONCompat.parse(read, :create_additions => false)) rescue Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}") end diff --git a/lib/chef/chef_fs/file_system/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb index b7ee51d284..273caa3478 100644 --- a/lib/chef/chef_fs/file_system/rest_list_dir.rb +++ b/lib/chef/chef_fs/file_system/rest_list_dir.rb @@ -19,6 +19,7 @@ require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' +require 'chef/json_compat' class Chef module ChefFS @@ -61,8 +62,8 @@ class Chef def create_child(name, file_contents) begin - object = JSON.parse(file_contents, :create_additions => false) - rescue JSON::ParserError => e + object = Chef::JSONCompat.parse(file_contents, :create_additions => false) + rescue Chef::Exceptions::JSON::ParseError => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Parse error reading JSON creating child '#{name}': #{e}" end diff --git a/lib/chef/chef_fs/file_system/rest_list_entry.rb b/lib/chef/chef_fs/file_system/rest_list_entry.rb index 0d5557de1d..345fab63be 100644 --- a/lib/chef/chef_fs/file_system/rest_list_entry.rb +++ b/lib/chef/chef_fs/file_system/rest_list_entry.rb @@ -19,6 +19,7 @@ require 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/operation_failed_error' +require 'chef/json_compat' require 'chef/role' require 'chef/node' @@ -128,8 +129,8 @@ class Chef value = minimize_value(value) value_json = Chef::JSONCompat.to_json_pretty(value) begin - other_value = JSON.parse(other_value_json, :create_additions => false) - rescue JSON::ParserError => e + other_value = Chef::JSONCompat.parse(other_value_json, :create_additions => false) + rescue Chef::Exceptions::JSON::ParseError => e Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}") return [ nil, value_json, other_value_json ] end @@ -145,8 +146,8 @@ class Chef def write(file_contents) begin - object = JSON.parse(file_contents, :create_additions => false) - rescue JSON::ParserError => e + object = Chef::JSONCompat.parse(file_contents, :create_additions => false) + rescue Chef::Exceptions::JSON::ParseError => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Parse error reading JSON: #{e}" end diff --git a/lib/chef/config_fetcher.rb b/lib/chef/config_fetcher.rb index c1fd262656..1d0693eaa2 100644 --- a/lib/chef/config_fetcher.rb +++ b/lib/chef/config_fetcher.rb @@ -18,7 +18,7 @@ class Chef config_data = read_config begin Chef::JSONCompat.from_json(config_data) - rescue FFI_Yajl::ParseError => error + rescue Chef::Exceptions::JSON::ParseError => error Chef::Application.fatal!("Could not parse the provided JSON file (#{config_location}): " + error.message, 2) end end diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb index 4e92b74ae9..fac8c80993 100644 --- a/lib/chef/cookbook/cookbook_version_loader.rb +++ b/lib/chef/cookbook/cookbook_version_loader.rb @@ -170,7 +170,7 @@ class Chef def apply_ruby_metadata(file) begin @metadata.from_file(file) - rescue JSON::ParserError + rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Error evaluating metadata.rb for #@cookbook_name in " + file) raise end @@ -179,7 +179,7 @@ class Chef def apply_json_metadata(file) begin @metadata.from_json(IO.read(file)) - rescue JSON::ParserError + rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@cookbook_name in " + file) raise end @@ -189,7 +189,7 @@ class Chef begin data = Chef::JSONCompat.from_json(IO.read(file), :create_additions => false) @metadata.from_hash(data['metadata']) - rescue JSON::ParserError + rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@cookbook_name in " + file) raise end @@ -200,7 +200,7 @@ class Chef begin data = Chef::JSONCompat.from_json(IO.read(uploaded_cookbook_version_file), :create_additions => false) @frozen = data['frozen?'] - rescue JSON::ParserError + rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@cookbook_name in #{uploaded_cookbook_version_file}") raise end diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb index 7da1ae70de..21ab72e1cd 100644 --- a/lib/chef/cookbook/metadata.rb +++ b/lib/chef/cookbook/metadata.rb @@ -441,7 +441,7 @@ class Chef end def to_json(*a) - self.to_hash.to_json(*a) + Chef::JSONCompat.to_json(self.to_hash, *a) end def self.from_hash(o) diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb index 3d8b9fb908..f9775c4d8d 100644 --- a/lib/chef/cookbook_version.rb +++ b/lib/chef/cookbook_version.rb @@ -459,7 +459,7 @@ class Chef def to_json(*a) result = self.to_hash result['json_class'] = self.class.name - result.to_json(*a) + Chef::JSONCompat.to_json(result, *a) end def self.json_create(o) @@ -469,7 +469,7 @@ class Chef cookbook_version.manifest = o # We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>) - cookbook_version.manifest["metadata"] = Chef::JSONCompat.from_json(cookbook_version.metadata.to_json) + cookbook_version.manifest["metadata"] = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(cookbook_version.metadata)) cookbook_version.freeze_version if o["frozen?"] cookbook_version diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb index 639d71a74d..f50aa93d2d 100644 --- a/lib/chef/data_bag.rb +++ b/lib/chef/data_bag.rb @@ -63,7 +63,7 @@ class Chef # Serialize this object as a hash def to_json(*a) - to_hash.to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) end def chef_server_rest diff --git a/lib/chef/data_bag_item.rb b/lib/chef/data_bag_item.rb index 07dd15a1dc..3772f9ea1c 100644 --- a/lib/chef/data_bag_item.rb +++ b/lib/chef/data_bag_item.rb @@ -118,7 +118,7 @@ class Chef "data_bag" => self.data_bag, "raw_data" => self.raw_data } - result.to_json(*a) + Chef::JSONCompat.to_json(result, *a) end def self.from_hash(h) diff --git a/lib/chef/encrypted_data_bag_item/decryptor.rb b/lib/chef/encrypted_data_bag_item/decryptor.rb index 69b8d62e3b..503a8f3099 100644 --- a/lib/chef/encrypted_data_bag_item/decryptor.rb +++ b/lib/chef/encrypted_data_bag_item/decryptor.rb @@ -17,10 +17,10 @@ # require 'yaml' -require 'ffi_yajl' require 'openssl' require 'base64' require 'digest/sha2' +require 'chef/json_compat' require 'chef/encrypted_data_bag_item' require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format' require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format' @@ -121,8 +121,8 @@ class Chef::EncryptedDataBagItem end def for_decrypted_item - FFI_Yajl::Parser.parse(decrypted_data)["json_wrapper"] - rescue FFI_Yajl::ParseError + Chef::JSONCompat.parse(decrypted_data)["json_wrapper"] + rescue Chef::Exceptions::JSON::ParseError # convert to a DecryptionFailure error because the most likely scenario # here is that the decryption step was unsuccessful but returned bad # data rather than raising an error. diff --git a/lib/chef/environment.rb b/lib/chef/environment.rb index 5c719ca285..3620ee0b7c 100644 --- a/lib/chef/environment.rb +++ b/lib/chef/environment.rb @@ -129,7 +129,7 @@ class Chef end def to_json(*a) - to_hash.to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) end def update_from!(o) diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb index 9ea40f71f6..2e7a92ab6f 100644 --- a/lib/chef/exceptions.rb +++ b/lib/chef/exceptions.rb @@ -267,7 +267,7 @@ class Chef "non_existent_cookbooks" => non_existent_cookbooks, "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions } - result.to_json(*a) + Chef::JSONCompat.to_json(result, *a) end end @@ -302,7 +302,7 @@ class Chef "non_existent_cookbooks" => non_existent_cookbooks, "most_constrained_cookbooks" => most_constrained_cookbooks } - result.to_json(*a) + Chef::JSONCompat.to_json(result, *a) end end @@ -337,5 +337,11 @@ class Chef end class BadProxyURI < RuntimeError; end + + # Raised by Chef::JSONCompat + class JSON + class EncodeError < RuntimeError; end + class ParseError < RuntimeError; end + end end end diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb index 2dbb607d9b..2a2d2df9ee 100644 --- a/lib/chef/json_compat.rb +++ b/lib/chef/json_compat.rb @@ -19,6 +19,7 @@ require 'ffi_yajl' require 'ffi_yajl/json_gem' # XXX: parts of chef require JSON gem's Hash#to_json monkeypatch +require 'chef/exceptions' class Chef class JSONCompat @@ -40,15 +41,24 @@ class Chef class <<self + # API to use to avoid create_addtions + def parse(source, opts = {}) + begin + FFI_Yajl::Parser.parse(source, opts) + rescue FFI_Yajl::ParseError => e + raise Chef::Exceptions::JSON::ParseError, e.message + end + end + # Just call the JSON gem's parse method with a modified :max_nesting field def from_json(source, opts = {}) - obj = ::FFI_Yajl::Parser.parse(source) + obj = parse(source, opts) # JSON gem requires top level object to be a Hash or Array (otherwise # you get the "must contain two octets" error). Yajl doesn't impose the # same limitation. For compatibility, we re-impose this condition. unless obj.kind_of?(Hash) or obj.kind_of?(Array) - raise JSON::ParserError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})" + raise Chef::Exceptions::JSON::ParseError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})" end # The old default in the json gem (which we are mimicing because we @@ -66,17 +76,17 @@ class Chef # to an instance of Chef classes if desired. def map_to_rb_obj(json_obj) case json_obj - when Hash - mapped_hash = map_hash_to_rb_obj(json_obj) - if json_obj.has_key?(JSON_CLASS) && (class_to_inflate = class_for_json_class(json_obj[JSON_CLASS])) - class_to_inflate.json_create(mapped_hash) + when Hash + mapped_hash = map_hash_to_rb_obj(json_obj) + if json_obj.has_key?(JSON_CLASS) && (class_to_inflate = class_for_json_class(json_obj[JSON_CLASS])) + class_to_inflate.json_create(mapped_hash) + else + mapped_hash + end + when Array + json_obj.map {|e| map_to_rb_obj(e) } else - mapped_hash - end - when Array - json_obj.map {|e| map_to_rb_obj(e) } - else - json_obj + json_obj end end @@ -88,52 +98,60 @@ class Chef end def to_json(obj, opts = nil) - obj.to_json(opts) + begin + FFI_Yajl::Encoder.encode(obj, opts) + rescue FFI_Yajl::EncodeError => e + raise Chef::Exceptions::JSON::EncodeError, e.message + end end def to_json_pretty(obj, opts = nil) - ::JSON.pretty_generate(obj, opts) + opts ||= {} + options_map = {} + options_map[:pretty] = true + options_map[:indent] = opts[:indent] if opts.has_key?(:indent) + to_json(obj, options_map).chomp end - # Map +json_class+ to a Class object. We use a +case+ instead of a Hash # assigned to a constant because otherwise this file could not be loaded # until all the constants were defined, which means you'd have to load # the world to get json, which would make knife very slow. def class_for_json_class(json_class) case json_class - when CHEF_APICLIENT - Chef::ApiClient - when CHEF_CHECKSUM - Chef::Checksum - when CHEF_COOKBOOKVERSION - Chef::CookbookVersion - when CHEF_DATABAG - Chef::DataBag - when CHEF_DATABAGITEM - Chef::DataBagItem - when CHEF_ENVIRONMENT - Chef::Environment - when CHEF_NODE - Chef::Node - when CHEF_ROLE - Chef::Role - when CHEF_SANDBOX - # a falsey return here will disable object inflation/"create - # additions" in the caller. In Chef 11 this is correct, we just have - # a dummy Chef::Sandbox class for compat with Chef 10 servers. - false - when CHEF_RESOURCE - Chef::Resource - when CHEF_RESOURCECOLLECTION - Chef::ResourceCollection - when /^Chef::Resource/ - Chef::Resource.find_subclass_by_name(json_class) - else - raise JSON::ParserError, "Unsupported `json_class` type '#{json_class}'" + when CHEF_APICLIENT + Chef::ApiClient + when CHEF_CHECKSUM + Chef::Checksum + when CHEF_COOKBOOKVERSION + Chef::CookbookVersion + when CHEF_DATABAG + Chef::DataBag + when CHEF_DATABAGITEM + Chef::DataBagItem + when CHEF_ENVIRONMENT + Chef::Environment + when CHEF_NODE + Chef::Node + when CHEF_ROLE + Chef::Role + when CHEF_SANDBOX + # a falsey return here will disable object inflation/"create + # additions" in the caller. In Chef 11 this is correct, we just have + # a dummy Chef::Sandbox class for compat with Chef 10 servers. + false + when CHEF_RESOURCE + Chef::Resource + when CHEF_RESOURCECOLLECTION + Chef::ResourceCollection + when /^Chef::Resource/ + Chef::Resource.find_subclass_by_name(json_class) + else + raise Chef::Exceptions::JSON::ParseError, "Unsupported `json_class` type '#{json_class}'" end end end end end + diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb index 46cacbd3e0..d3d45bad4b 100644 --- a/lib/chef/knife/bootstrap.rb +++ b/lib/chef/knife/bootstrap.rb @@ -126,7 +126,7 @@ class Chef :short => "-j JSON_ATTRIBS", :long => "--json-attributes", :description => "A JSON string to be added to the first run of chef-client", - :proc => lambda { |o| JSON.parse(o) }, + :proc => lambda { |o| Chef::JSONCompat.parse(o) }, :default => {} option :host_key_verify, @@ -141,7 +141,7 @@ class Chef :proc => Proc.new { |h| Chef::Config[:knife][:hints] ||= Hash.new name, path = h.split("=") - Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new } + Chef::Config[:knife][:hints][name] = path ? Chef::JSONCompat.parse(::File.read(path)) : Hash.new } option :secret, :short => "-s SECRET", diff --git a/lib/chef/knife/bootstrap/archlinux-gems.erb b/lib/chef/knife/bootstrap/archlinux-gems.erb index ab2aa7a7f1..35133e23e5 100644 --- a/lib/chef/knife/bootstrap/archlinux-gems.erb +++ b/lib/chef/knife/bootstrap/archlinux-gems.erb @@ -29,7 +29,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -56,7 +56,7 @@ https_proxy "<%= knife_config[:bootstrap_proxy] %>" EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/centos5-gems.erb b/lib/chef/knife/bootstrap/centos5-gems.erb index 6aacc47179..30418eca2d 100644 --- a/lib/chef/knife/bootstrap/centos5-gems.erb +++ b/lib/chef/knife/bootstrap/centos5-gems.erb @@ -46,7 +46,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -56,7 +56,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/chef-aix.erb b/lib/chef/knife/bootstrap/chef-aix.erb index 59993b478a..3985415d73 100644 --- a/lib/chef/knife/bootstrap/chef-aix.erb +++ b/lib/chef/knife/bootstrap/chef-aix.erb @@ -42,7 +42,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -52,7 +52,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/chef-full.erb b/lib/chef/knife/bootstrap/chef-full.erb index c953a7e433..cffe7007e9 100644 --- a/lib/chef/knife/bootstrap/chef-full.erb +++ b/lib/chef/knife/bootstrap/chef-full.erb @@ -57,7 +57,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -67,7 +67,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP echo "Starting first Chef Client run..." diff --git a/lib/chef/knife/bootstrap/fedora13-gems.erb b/lib/chef/knife/bootstrap/fedora13-gems.erb index 0aabc31085..431d2bdb00 100644 --- a/lib/chef/knife/bootstrap/fedora13-gems.erb +++ b/lib/chef/knife/bootstrap/fedora13-gems.erb @@ -28,7 +28,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -38,7 +38,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb b/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb index 4549b94d2b..d95de60149 100644 --- a/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +++ b/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb @@ -28,7 +28,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -47,7 +47,7 @@ echo 'https_proxy "knife_config[:bootstrap_proxy]"' >> /etc/chef/client.rb <% end -%> cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb b/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb index 62ff7c857e..8e41c8f059 100644 --- a/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +++ b/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb @@ -32,7 +32,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -42,7 +42,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb b/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb index 8e9c6583d0..b6a5aee7e7 100644 --- a/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb +++ b/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb @@ -30,7 +30,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP <% end -%> <% end -%> @@ -40,7 +40,7 @@ cat > /etc/chef/client.rb <<'EOP' EOP cat > /etc/chef/first-boot.json <<'EOP' -<%= first_boot.to_json %> +<%= Chef::JSONCompat.to_json(first_boot) %> EOP <%= start_chef %>' diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb index 4dcce42d7f..2de0f9c5f3 100644 --- a/lib/chef/knife/cookbook_site_share.rb +++ b/lib/chef/knife/cookbook_site_share.rb @@ -87,7 +87,7 @@ class Chef def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename) uri = "http://cookbooks.opscode.com/api/v1/cookbooks" - category_string = { 'category'=>cookbook_category }.to_json + category_string = Chef::JSONCompat.to_json({ 'category'=>cookbook_category }) http_resp = Chef::CookbookSiteStreamingUploader.post(uri, user_id, user_secret_filename, { :tarball => File.open(cookbook_filename), diff --git a/lib/chef/knife/deps.rb b/lib/chef/knife/deps.rb index b2a39a0725..89fd42124f 100644 --- a/lib/chef/knife/deps.rb +++ b/lib/chef/knife/deps.rb @@ -9,6 +9,7 @@ class Chef deps do require 'chef/chef_fs/file_system' + require 'chef/json_compat' require 'chef/run_list' end @@ -77,7 +78,7 @@ class Chef return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" } elsif entry.parent && entry.parent.path == '/nodes' - node = JSON.parse(entry.read, :create_additions => false) + node = Chef::JSONCompat.parse(entry.read, :create_additions => false) result = [] if node['chef_environment'] && node['chef_environment'] != '_default' result << "/environments/#{node['chef_environment']}.json" @@ -88,7 +89,7 @@ class Chef result elsif entry.parent && entry.parent.path == '/roles' - role = JSON.parse(entry.read, :create_additions => false) + role = Chef::JSONCompat.parse(entry.read, :create_additions => false) result = [] if role['run_list'] dependencies_from_runlist(role['run_list']).each do |dependency| diff --git a/lib/chef/node.rb b/lib/chef/node.rb index 17ec1d0f0a..261c4a3f10 100644 --- a/lib/chef/node.rb +++ b/lib/chef/node.rb @@ -416,7 +416,7 @@ class Chef # Serialize this object as a hash def to_json(*a) - for_json.to_json(*a) + Chef::JSONCompat.to_json(for_json, *a) end def for_json diff --git a/lib/chef/provider/deploy/revision.rb b/lib/chef/provider/deploy/revision.rb index f1eb171cd7..89710088d1 100644 --- a/lib/chef/provider/deploy/revision.rb +++ b/lib/chef/provider/deploy/revision.rb @@ -97,7 +97,7 @@ class Chef end def save_cache(cache) - Chef::FileCache.store("revision-deploys/#{new_resource.name}", cache.to_json) + Chef::FileCache.store("revision-deploys/#{new_resource.name}", Chef::JSONCompat.to_json(cache)) cache end diff --git a/lib/chef/provider/remote_file/cache_control_data.rb b/lib/chef/provider/remote_file/cache_control_data.rb index 0add74f50a..95b2bc6a1b 100644 --- a/lib/chef/provider/remote_file/cache_control_data.rb +++ b/lib/chef/provider/remote_file/cache_control_data.rb @@ -140,7 +140,7 @@ class Chef def load_data Chef::JSONCompat.from_json(load_json_data) - rescue Chef::Exceptions::FileNotFound, FFI_Yajl::ParseError, JSON::ParserError + rescue Chef::Exceptions::FileNotFound, FFI_Yajl::ParseError, Chef::Exceptions::JSON::ParseError false end diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index f6283e4033..a112e3b463 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -544,7 +544,7 @@ F # Serialize this object as a hash def to_json(*a) results = as_json - results.to_json(*a) + Chef::JSONCompat.to_json(results, *a) end def to_hash diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb index a528a18aed..3097707a13 100644 --- a/lib/chef/resource_collection.rb +++ b/lib/chef/resource_collection.rb @@ -198,7 +198,7 @@ class Chef 'json_class' => self.class.name, 'instance_vars' => instance_vars } - results.to_json(*a) + Chef::JSONCompat.to_json(results, *a) end def self.json_create(o) diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb index 046e4e82c6..a19f26125e 100644 --- a/lib/chef/resource_reporter.rb +++ b/lib/chef/resource_reporter.rb @@ -230,7 +230,7 @@ class Chef resource_history_url = "reports/nodes/#{node_name}/runs/#{run_id}" Chef::Log.info("Sending resource update report (run-id: #{run_id})") Chef::Log.debug run_data.inspect - compressed_data = encode_gzip(run_data.to_json) + compressed_data = encode_gzip(Chef::JSONCompat.to_json(run_data)) Chef::Log.debug("Sending compressed run data...") # Since we're posting compressed data we can not directly call post_rest which expects JSON reporting_url = @rest_client.create_url(resource_history_url) @@ -273,7 +273,7 @@ class Chef resource_record.for_json end run_data["status"] = @status - run_data["run_list"] = @run_status.node.run_list.to_json + run_data["run_list"] = Chef::JSONCompat.to_json(@run_status.node.run_list) run_data["total_res_count"] = @total_res_count.to_s run_data["data"] = {} run_data["start_time"] = start_time.to_s @@ -283,7 +283,7 @@ class Chef exception_data = {} exception_data["class"] = exception.inspect exception_data["message"] = exception.message - exception_data["backtrace"] = exception.backtrace.to_json + exception_data["backtrace"] = Chef::JSONCompat.to_json(exception.backtrace) exception_data["description"] = @error_descriptions run_data["data"]["exception"] = exception_data end diff --git a/lib/chef/role.rb b/lib/chef/role.rb index 57f3a2aa29..aeea873051 100644 --- a/lib/chef/role.rb +++ b/lib/chef/role.rb @@ -143,7 +143,7 @@ class Chef # Serialize this object as a hash def to_json(*a) - to_hash.to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) end def update_from!(o) diff --git a/lib/chef/run_list.rb b/lib/chef/run_list.rb index 684c5e19fc..d0ba342e2c 100644 --- a/lib/chef/run_list.rb +++ b/lib/chef/run_list.rb @@ -86,7 +86,7 @@ class Chef end def to_json(*args) - to_a.map { |item| item.to_s}.to_json(*args) + Chef::JSONCompat.to_json(to_a.map { |item| item.to_s}, *args) end def empty? diff --git a/lib/chef/user.rb b/lib/chef/user.rb index e2ef45dc5c..6569a97f00 100644 --- a/lib/chef/user.rb +++ b/lib/chef/user.rb @@ -73,7 +73,7 @@ class Chef end def to_json(*a) - to_hash.to_json(*a) + Chef::JSONCompat.to_json(to_hash, *a) end def destroy diff --git a/lib/chef/util/powershell/cmdlet_result.rb b/lib/chef/util/powershell/cmdlet_result.rb index af7b3607cd..246701a7bc 100644 --- a/lib/chef/util/powershell/cmdlet_result.rb +++ b/lib/chef/util/powershell/cmdlet_result.rb @@ -16,7 +16,7 @@ # limitations under the License. # -require 'json' +require 'chef/json_compat' class Chef::Util::Powershell class CmdletResult @@ -33,7 +33,7 @@ class Chef::Util::Powershell def return_value if output_format == :object - JSON.parse(@status.stdout) + Chef::JSONCompat.parse(@status.stdout) else @status.stdout end diff --git a/spec/data/bootstrap/test-hints.erb b/spec/data/bootstrap/test-hints.erb index 29ba710b42..7693fdc7c9 100644 --- a/spec/data/bootstrap/test-hints.erb +++ b/spec/data/bootstrap/test-hints.erb @@ -6,7 +6,7 @@ mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> ( cat <<'EOP' -<%= hash.to_json %> +<%= Chef::JSONCompat.to_json(hash) %> EOP ) > /etc/chef/ohai/hints/<%= name %>.json <% end -%> diff --git a/spec/data/bootstrap/test.erb b/spec/data/bootstrap/test.erb index 7cdc7dfdd0..3a383b47d0 100644 --- a/spec/data/bootstrap/test.erb +++ b/spec/data/bootstrap/test.erb @@ -1 +1 @@ -<%= first_boot.to_json %>
\ No newline at end of file +<%= Chef::JSONCompat.to_json(first_boot) %> diff --git a/spec/functional/knife/cookbook_delete_spec.rb b/spec/functional/knife/cookbook_delete_spec.rb index ee620bf165..4773fd2185 100644 --- a/spec/functional/knife/cookbook_delete_spec.rb +++ b/spec/functional/knife/cookbook_delete_spec.rb @@ -47,7 +47,7 @@ describe Chef::Knife::CookbookDelete do Chef::Log.level = :debug @knife.name_args = %w{no-such-cookbook} - @api.get("/cookbooks/no-such-cookbook", 404, {'error'=>'dear Tim, no. -Sent from my iPad'}.to_json) + @api.get("/cookbooks/no-such-cookbook", 404, Chef::JSONCompat.to_json({'error'=>'dear Tim, no. -Sent from my iPad'})) end it "logs an error and exits" do @@ -62,7 +62,7 @@ describe Chef::Knife::CookbookDelete do before do @knife.name_args = %w{obsolete-cookbook} @cookbook_list = {'obsolete-cookbook' => { 'versions' => ['version' => '1.0.0']} } - @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) + @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list)) end it "asks for confirmation, then deletes the cookbook" do @@ -105,7 +105,7 @@ describe Chef::Knife::CookbookDelete do versions = ['1.0.0', '1.1.0', '1.2.0'] with_version = lambda { |version| { 'version' => version } } @cookbook_list = {'obsolete-cookbook' => { 'versions' => versions.map(&with_version) } } - @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) + @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list)) end it "deletes all versions of a cookbook when given the '-a' flag" do diff --git a/spec/functional/knife/exec_spec.rb b/spec/functional/knife/exec_spec.rb index 455160fd5c..7eb52d01df 100644 --- a/spec/functional/knife/exec_spec.rb +++ b/spec/functional/knife/exec_spec.rb @@ -47,7 +47,7 @@ describe Chef::Knife::Exec do @node = Chef::Node.new @node.name("ohai-world") response = {"rows" => [@node],"start" => 0,"total" => 1} - @api.get(%r{^/search/node}, 200, response.to_json) + @api.get(%r{^/search/node}, 200, Chef::JSONCompat.to_json(response)) code = "$output.puts nodes.all" @knife.config[:exec] = code @knife.run diff --git a/spec/functional/util/powershell/cmdlet_spec.rb b/spec/functional/util/powershell/cmdlet_spec.rb index 63d1ac09b5..ca142e66b6 100644 --- a/spec/functional/util/powershell/cmdlet_spec.rb +++ b/spec/functional/util/powershell/cmdlet_spec.rb @@ -16,7 +16,6 @@ # limitations under the License. # -require 'json' require File.expand_path('../../../../spec_helper', __FILE__) describe Chef::Util::Powershell::Cmdlet, :windows_only do @@ -91,7 +90,7 @@ describe Chef::Util::Powershell::Cmdlet, :windows_only do it "returns json format data", :windows_powershell_dsc_only do result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls') expect(result.succeeded?).to eq(true) - expect(lambda{JSON.parse(result.return_value)}).not_to raise_error + expect(lambda{Chef::JSONCompat.parse(result.return_value)}).not_to raise_error end end diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb index 46b804205f..9ae48062fc 100644 --- a/spec/integration/knife/upload_spec.rb +++ b/spec/integration/knife/upload_spec.rb @@ -237,7 +237,7 @@ Created /data_bags/x/y.json EOM knife('diff --name-status /data_bags').should_succeed <<EOM EOM - JSON.parse(knife('raw /data/x/y').stdout, :create_additions => false).keys.sort.should == [ 'foo', 'id' ] + Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false).keys.sort.should == [ 'foo', 'id' ] end it 'knife upload /data_bags/x /data_bags/x/y.json uploads x once' do @@ -256,7 +256,7 @@ Created /data_bags/x Created /data_bags/x/y.json EOM knife('diff --name-status /data_bags').should_succeed '' - result = JSON.parse(knife('raw /data/x/y').stdout, :create_additions => false) + result = Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false) result.keys.sort.should == [ 'chef_type', 'data_bag', 'id' ] result['chef_type'].should == 'aaa' result['data_bag'].should == 'bbb' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e73010d2b5..e0788f3d9c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -182,3 +182,13 @@ module WEBrick end end end + +# We are no longer using the 'json' gem - deny all access to it! +orig_require = Kernel.send(:instance_method, :require) +Kernel.send(:remove_method, :require) +Kernel.send(:define_method, :require) { |path| + raise LoadError, 'JSON gem is no longer allowed - use Chef::JSONCompat.to_json' if path == 'json' + orig_require.bind(Kernel).call(path) + } +# Enough stuff needs json serialization that I'm just adding it here for equality asserts +require 'chef/json_compat' diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb index abed4c2715..d262e58b48 100644 --- a/spec/support/shared/integration/integration_helper.rb +++ b/spec/support/shared/integration/integration_helper.rb @@ -21,7 +21,6 @@ require 'tmpdir' require 'fileutils' require 'chef/config' require 'chef_zero/rspec' -require 'json' require 'support/shared/integration/knife_support' require 'support/shared/integration/app_server_support' require 'spec_helper' @@ -69,7 +68,7 @@ module IntegrationSupport File.open(filename, 'w') do |file| raw = case contents when Hash - JSON.pretty_generate(contents) + Chef::JSONCompat.to_json_pretty(contents) when Array contents.join("\n") else diff --git a/spec/support/shared/shared_examples.rb b/spec/support/shared/shared_examples.rb new file mode 100644 index 0000000000..ccdd8cf316 --- /dev/null +++ b/spec/support/shared/shared_examples.rb @@ -0,0 +1,10 @@ +# For storing any examples shared between multiple tests + +# Any object which defines a .to_json should import this test +shared_examples "to_json equalivent to Chef::JSONCompat.to_json" do + + it "should allow consumers to call #to_json or Chef::JSONCompat.to_json" do + expect(subject.to_json).to eq(Chef::JSONCompat.to_json(subject)) + end + +end diff --git a/spec/tiny_server.rb b/spec/tiny_server.rb index 7e6ef3a809..848e2f1133 100644 --- a/spec/tiny_server.rb +++ b/spec/tiny_server.rb @@ -25,6 +25,7 @@ require 'singleton' require 'chef/json_compat' require 'open-uri' require 'chef/config' +require 'chef/json_compat' module TinyServer @@ -152,7 +153,7 @@ module TinyServer :available_routes => @routes, :request => env} # Uncomment me for glorious debugging # pp :not_found => debug_info - [404, {'Content-Type' => 'application/json'}, [ debug_info.to_json ]] + [404, {'Content-Type' => 'application/json'}, [ Chef::JSONCompat.to_json(debug_info) ]] end end diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb index 76fc4afb5c..14dcc60467 100644 --- a/spec/unit/api_client_spec.rb +++ b/spec/unit/api_client_spec.rb @@ -92,7 +92,7 @@ describe Chef::ApiClient do before(:each) do @client.name("black") @client.public_key("crowes") - @json = @client.to_json + @json = Chef::JSONCompat.to_json(@client) end it "serializes as a JSON object" do @@ -117,7 +117,7 @@ describe Chef::ApiClient do it "includes the private key when present" do @client.private_key("monkeypants") - @client.to_json.should include(%q{"private_key":"monkeypants"}) + Chef::JSONCompat.to_json(@client).should include(%q{"private_key":"monkeypants"}) end it "does not include the private key if not present" do @@ -135,7 +135,7 @@ describe Chef::ApiClient do "validator" => true, "json_class" => "Chef::ApiClient" } - @client = Chef::JSONCompat.from_json(client.to_json) + @client = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(client)) end it "should deserialize to a Chef::ApiClient object" do diff --git a/spec/unit/config_fetcher_spec.rb b/spec/unit/config_fetcher_spec.rb index c29521806a..66681b85ab 100644 --- a/spec/unit/config_fetcher_spec.rb +++ b/spec/unit/config_fetcher_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'chef/config_fetcher' describe Chef::ConfigFetcher do - let(:valid_json) { {:a=>"b"}.to_json } + let(:valid_json) { Chef::JSONCompat.to_json({:a=>"b"}) } let(:invalid_json) { %q[{"syntax-error": "missing quote}] } let(:http) { double("Chef::HTTP::Simple") } diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb index 8e98610183..24c9a48b81 100644 --- a/spec/unit/cookbook/metadata_spec.rb +++ b/spec/unit/cookbook/metadata_spec.rb @@ -582,7 +582,7 @@ describe Chef::Cookbook::Metadata do @meta.version "1.2.3" end - describe "serialize" do + describe "#to_json" do before(:each) do @serial = Chef::JSONCompat.from_json(@meta.to_json) end @@ -613,11 +613,15 @@ describe Chef::Cookbook::Metadata do @serial[t].should == @meta.send(t.to_sym) end end + + it "should produce the same output from to_json and Chef::JSONCompat" do + expect(@meta.to_json).to eq(Chef::JSONCompat.to_json(@meta)) + end end - describe "deserialize" do + describe "::from_json" do before(:each) do - @deserial = Chef::Cookbook::Metadata.from_json(@meta.to_json) + @deserial = Chef::Cookbook::Metadata.from_json(Chef::JSONCompat.to_json(@meta)) end it "should deserialize to a Chef::Cookbook::Metadata object" do diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb index 4c21c124e0..2bcba07eb2 100644 --- a/spec/unit/cookbook_loader_spec.rb +++ b/spec/unit/cookbook_loader_spec.rb @@ -181,7 +181,7 @@ describe Chef::CookbookLoader do aa.to_hash["metadata"].recipes.keys.should include("openldap") expected_desc = "Main Open LDAP configuration" aa.to_hash["metadata"].recipes["openldap"].should == expected_desc - raw = aa.to_hash["metadata"].recipes.to_json + raw = Chef::JSONCompat.to_json(aa.to_hash["metadata"].recipes) search_str = "\"openldap\":\"" key_idx = raw.index(search_str) key_idx.should be > 0 diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb index f20bc3766a..ea36dcc6d8 100644 --- a/spec/unit/cookbook_version_spec.rb +++ b/spec/unit/cookbook_version_spec.rb @@ -420,6 +420,10 @@ describe Chef::CookbookVersion do end end + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { Chef::CookbookVersion.new("tatft", '/tmp/blah') } + end + end end diff --git a/spec/unit/data_bag_item_spec.rb b/spec/unit/data_bag_item_spec.rb index ead0dadfa2..f28450ef72 100644 --- a/spec/unit/data_bag_item_spec.rb +++ b/spec/unit/data_bag_item_spec.rb @@ -166,7 +166,7 @@ describe Chef::DataBagItem do before(:each) do @data_bag_item.data_bag('mars_volta') @data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will }} - @deserial = Chef::JSONCompat.from_json(@data_bag_item.to_json) + @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data_bag_item)) end it "should deserialize to a Chef::DataBagItem object" do @@ -184,6 +184,10 @@ describe Chef::DataBagItem do it "should have a matching 'snooze' key" do @deserial["snooze"].should == { "finally" => "world_will" } end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @data_bag_item } + end end describe "when converting to a string" do diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb index 4ac843c869..b1c4b0ea6f 100644 --- a/spec/unit/data_bag_spec.rb +++ b/spec/unit/data_bag_spec.rb @@ -58,7 +58,7 @@ describe Chef::DataBag do describe "deserialize" do before(:each) do @data_bag.name('mars_volta') - @deserial = Chef::JSONCompat.from_json(@data_bag.to_json) + @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data_bag)) end it "should deserialize to a Chef::DataBag object" do @@ -73,6 +73,10 @@ describe Chef::DataBag do end end + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @data_bag } + end + end describe "when saving" do diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb index 8617cb3cb3..6a405c2bb6 100644 --- a/spec/unit/deprecation_spec.rb +++ b/spec/unit/deprecation_spec.rb @@ -46,7 +46,7 @@ describe Chef::Deprecation do end method_snapshot_file = File.join(CHEF_SPEC_DATA, "file-providers-method-snapshot-chef-11-4.json") - method_snapshot = JSON.parse(File.open(method_snapshot_file).read()) + method_snapshot = Chef::JSONCompat.parse(File.open(method_snapshot_file).read()) method_snapshot.each do |class_name, old_methods| class_object = class_from_string(class_name) diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb index 1e662a0b7c..998b493514 100644 --- a/spec/unit/encrypted_data_bag_item_spec.rb +++ b/spec/unit/encrypted_data_bag_item_spec.rb @@ -100,6 +100,17 @@ describe Chef::EncryptedDataBagItem::Decryptor do let(:plaintext_data) { {"foo" => "bar"} } let(:encryption_key) { "passwd" } let(:decryption_key) { encryption_key } + let(:json_wrapped_data) { Chef::JSONCompat.to_json({"json_wrapper" => plaintext_data}) } + + shared_examples "decryption examples" do + it "decrypts the encrypted value" do + decryptor.decrypted_data.should eq(json_wrapped_data) + end + + it "unwraps the encrypted data and returns it" do + decryptor.for_decrypted_item.should eq plaintext_data + end + end context "when decrypting a version 2 (JSON+aes-256-cbc+hmac-sha256+random iv) encrypted value" do let(:encrypted_value) do @@ -112,6 +123,8 @@ describe Chef::EncryptedDataBagItem::Decryptor do Base64.encode64(raw_hmac) end + include_examples "decryption examples" + it "rejects the data if the hmac is wrong" do encrypted_value["hmac"] = bogus_hmac lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) @@ -134,13 +147,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do decryptor.should be_a_kind_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor end - it "decrypts the encrypted value" do - decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json) - end - - it "unwraps the encrypted data and returns it" do - decryptor.for_decrypted_item.should eq plaintext_data - end + include_examples "decryption examples" describe "and the decryption step returns invalid data" do it "raises a decryption failure error" do diff --git a/spec/unit/environment_spec.rb b/spec/unit/environment_spec.rb index 0e230e46ed..bb4ece0a47 100644 --- a/spec/unit/environment_spec.rb +++ b/spec/unit/environment_spec.rb @@ -196,7 +196,7 @@ describe Chef::Environment do %w{name description cookbook_versions}.each do |t| it "should include '#{t}'" do - @json.should =~ /"#{t}":#{Regexp.escape(@environment.send(t.to_sym).to_json)}/ + @json.should =~ /"#{t}":#{Regexp.escape(Chef::JSONCompat.to_json(@environment.send(t.to_sym)))}/ end end @@ -207,6 +207,10 @@ describe Chef::Environment do it "should include 'chef_type'" do @json.should =~ /"chef_type":"environment"/ end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @environment } + end end describe "from_json" do @@ -222,7 +226,7 @@ describe Chef::Environment do "json_class" => "Chef::Environment", "chef_type" => "environment" } - @environment = Chef::JSONCompat.from_json(@data.to_json) + @environment = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data)) end it "should return a Chef::Environment" do @@ -420,7 +424,7 @@ describe Chef::Environment do "description" => "desc", "chef_type" => "environment" } - IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(JSON.dump(environment_hash)) + IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(Chef::JSONCompat.to_json(environment_hash)) environment = Chef::Environment.load('foo') environment.should be_a_kind_of(Chef::Environment) diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb index 3e7b1ba93f..c7bfc63e6b 100644 --- a/spec/unit/exceptions_spec.rb +++ b/spec/unit/exceptions_spec.rb @@ -74,5 +74,11 @@ describe Chef::Exceptions do it "should have an exception class of #{exception} which inherits from #{expected_super_class}" do lambda{ raise exception }.should raise_error(expected_super_class) end + + if exception.methods.include?(:to_json) + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { exception } + end + end end end diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb index cce31b0c7c..5951f0cc47 100644 --- a/spec/unit/json_compat_spec.rb +++ b/spec/unit/json_compat_spec.rb @@ -21,49 +21,89 @@ require 'chef/json_compat' describe Chef::JSONCompat do - describe "with JSON containing an existing class" do - let(:json){'{"json_class": "Chef::Role"}'} + describe "#from_json with JSON containing an existing class" do + let(:json) { '{"json_class": "Chef::Role"}' } + it "returns an instance of the class instead of a Hash" do - Chef::JSONCompat.from_json(json).class.should eq Chef::Role + expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role + end + end + + describe "#from_json with JSON containing comments" do + let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} } + + it "returns an instance of the class instead of a Hash" do + expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role + end + end + + describe "#parse with JSON containing comments" do + let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} } + + it "returns a Hash" do + expect(Chef::JSONCompat.parse(json).class).to eq Hash end end describe 'with JSON containing "Chef::Sandbox" as a json_class value' do require 'chef/sandbox' # Only needed for this test - let(:json){'{"json_class": "Chef::Sandbox", "arbitrary": "data"}'} + + let(:json) { '{"json_class": "Chef::Sandbox", "arbitrary": "data"}' } + it "returns a Hash, because Chef::Sandbox is a dummy class" do - Chef::JSONCompat.from_json(json).should eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"}) + expect(Chef::JSONCompat.from_json(json)).to eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"}) end end - describe "with a file with 300 or less nested entries" do - before(:all) do - @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) - @hash = Chef::JSONCompat.from_json(@json) + describe "when pretty printing an object that defines #to_json" do + class Foo + def to_json(*a) + Chef::JSONCompat.to_json({'foo' => 1234, 'bar' => {'baz' => 5678}}, *a) + end end + it "should work" do + f = Foo.new + expect(Chef::JSONCompat.to_json_pretty(f)).to eql("{\n \"foo\": 1234,\n \"bar\": {\n \"baz\": 5678\n }\n}\n") + end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { Foo.new } + end + end + + describe "with a file with 300 or less nested entries" do + let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) } + let(:hash) { Chef::JSONCompat.from_json(json) } + describe "when a big json file is loaded" do it "should create a Hash from the file" do - @hash.should be_kind_of(Hash) + expect(hash).to be_kind_of(Hash) end + it "should has 'test' as a 300th nested value" do - @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test' + expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test') end end end + describe "with a file with more than 300 nested entries" do - before(:all) do - @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) - @hash = Chef::JSONCompat.from_json(@json, {:max_nesting => 301}) - end + let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) } + let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) } describe "when a big json file is loaded" do it "should create a Hash from the file" do - @hash.should be_kind_of(Hash) + expect(hash).to be_kind_of(Hash) end + it "should has 'test' as a 301st nested value" do - @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test' + expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test') end end end + + it "should not allow the json gem to be required because of the spec_helper" do + # We want to prevent ourselves from writing code that requires 'json' + expect { require 'json' }.to raise_error(LoadError) + end end diff --git a/spec/unit/knife/cookbook_metadata_from_file_spec.rb b/spec/unit/knife/cookbook_metadata_from_file_spec.rb index 68ab6740ab..3a1dd9b21e 100644 --- a/spec/unit/knife/cookbook_metadata_from_file_spec.rb +++ b/spec/unit/knife/cookbook_metadata_from_file_spec.rb @@ -27,7 +27,6 @@ describe Chef::Knife::CookbookMetadataFromFile do @tgt = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.json")) @knife = Chef::Knife::CookbookMetadataFromFile.new @knife.name_args = [ @src ] - @knife.stub(:to_json_pretty).and_return(true) @md = Chef::Cookbook::Metadata.new Chef::Cookbook::Metadata.stub(:new).and_return(@md) $stdout.stub(:write) diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb index 28b2a509fd..7e4a65ae7e 100644 --- a/spec/unit/knife/cookbook_site_share_spec.rb +++ b/spec/unit/knife/cookbook_site_share_spec.rb @@ -109,7 +109,7 @@ describe Chef::Knife::CookbookSiteShare do end it 'should post the cookbook to "http://cookbooks.opscode.com"' do - response_text = {:uri => 'http://cookbooks.opscode.com/cookbooks/cookbook_name'}.to_json + response_text = Chef::JSONCompat.to_json({:uri => 'http://cookbooks.opscode.com/cookbooks/cookbook_name'}) @upload_response.stub(:body).and_return(response_text) @upload_response.stub(:code).and_return(201) Chef::CookbookSiteStreamingUploader.should_receive(:post).with(/cookbooks\.opscode\.com/, anything(), anything(), anything()) @@ -117,7 +117,7 @@ describe Chef::Knife::CookbookSiteShare do end it 'should alert the user when a version already exists' do - response_text = {:error_messages => ['Version already exists']}.to_json + response_text = Chef::JSONCompat.to_json({:error_messages => ['Version already exists']}) @upload_response.stub(:body).and_return(response_text) @upload_response.stub(:code).and_return(409) lambda { @knife.run }.should raise_error(SystemExit) @@ -125,7 +125,7 @@ describe Chef::Knife::CookbookSiteShare do end it 'should pass any errors on to the user' do - response_text = {:error_messages => ["You're holding it wrong"]}.to_json + response_text = Chef::JSONCompat.to_json({:error_messages => ["You're holding it wrong"]}) @upload_response.stub(:body).and_return(response_text) @upload_response.stub(:code).and_return(403) lambda { @knife.run }.should raise_error(SystemExit) @@ -133,7 +133,7 @@ describe Chef::Knife::CookbookSiteShare do end it 'should print the body if no errors are exposed on failure' do - response_text = {:system_error => "Your call was dropped", :reason => "There's a map for that"}.to_json + response_text = Chef::JSONCompat.to_json({:system_error => "Your call was dropped", :reason => "There's a map for that"}) @upload_response.stub(:body).and_return(response_text) @upload_response.stub(:code).and_return(500) @knife.ui.should_receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb index 9cabc59719..57c1934439 100644 --- a/spec/unit/knife/core/bootstrap_context_spec.rb +++ b/spec/unit/knife/core/bootstrap_context_spec.rb @@ -116,13 +116,13 @@ EXPECTED describe "when JSON attributes are given" do let(:config) { {:first_boot_attributes => {:baz => :quux}} } it "adds the attributes to first_boot" do - bootstrap_context.first_boot.to_json.should eq({:baz => :quux, :run_list => run_list}.to_json) + Chef::JSONCompat.to_json(bootstrap_context.first_boot).should eq(Chef::JSONCompat.to_json({:baz => :quux, :run_list => run_list})) end end describe "when JSON attributes are NOT given" do it "sets first_boot equal to run_list" do - bootstrap_context.first_boot.to_json.should eq({:run_list => run_list}.to_json) + Chef::JSONCompat.to_json(bootstrap_context.first_boot).should eq(Chef::JSONCompat.to_json({:run_list => run_list})) end end diff --git a/spec/unit/knife/data_bag_from_file_spec.rb b/spec/unit/knife/data_bag_from_file_spec.rb index 8537045164..0e53a67619 100644 --- a/spec/unit/knife/data_bag_from_file_spec.rb +++ b/spec/unit/knife/data_bag_from_file_spec.rb @@ -21,7 +21,6 @@ require 'spec_helper' require 'chef/data_bag_item' require 'chef/encrypted_data_bag_item' require 'tempfile' -require 'json' Chef::Knife::DataBagFromFile.load_deps @@ -46,7 +45,7 @@ describe Chef::Knife::DataBagFromFile do "greeting" => "hello", "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }} } - @db_file.write(@plain_data.to_json) + @db_file.write(Chef::JSONCompat.to_json(@plain_data)) @db_file.flush @knife.instance_variable_set(:@name_args, ['bag_name', @db_file.path]) end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index 21a978a9c9..ccecfca2f0 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -762,6 +762,10 @@ describe Chef::Node do end serialized_node.run_list.should == node.run_list end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA)) } + end end describe "to_s" do diff --git a/spec/unit/provider/remote_file/cache_control_data_spec.rb b/spec/unit/provider/remote_file/cache_control_data_spec.rb index 8e396b1b40..8a849d9d7d 100644 --- a/spec/unit/provider/remote_file/cache_control_data_spec.rb +++ b/spec/unit/provider/remote_file/cache_control_data_spec.rb @@ -85,7 +85,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do cache["etag"] = etag cache["mtime"] = mtime cache["checksum"] = last_fetched_checksum - cache.to_json + Chef::JSONCompat.to_json(cache) end before do diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb index cf62f5ff40..cc9cc83923 100644 --- a/spec/unit/resource_collection_spec.rb +++ b/spec/unit/resource_collection_spec.rb @@ -245,12 +245,16 @@ describe Chef::ResourceCollection do json.should =~ /json_class/ json.should =~ /instance_vars/ end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @rc } + end end describe "self.from_json" do it "should deserialize itself from json" do @rc << @resource - json = @rc.to_json + json = Chef::JSONCompat.to_json(@rc) s_rc = Chef::JSONCompat.from_json(json) s_rc.should be_a_kind_of(Chef::ResourceCollection) s_rc[0].name.should eql(@resource.name) diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb index fe6a895b5a..1a89cbdce1 100644 --- a/spec/unit/resource_reporter_spec.rb +++ b/spec/unit/resource_reporter_spec.rb @@ -421,7 +421,7 @@ describe Chef::ResourceReporter do it "includes the run_list" do @report.should have_key("run_list") - @report["run_list"].should == @run_status.node.run_list.to_json + @report["run_list"].should == Chef::JSONCompat.to_json(@run_status.node.run_list) end it "includes the end_time" do @@ -484,7 +484,7 @@ describe Chef::ResourceReporter do it "includes the exception trace in the event data" do @report["data"]["exception"].should have_key("backtrace") - @report["data"]["exception"]["backtrace"].should == @backtrace.to_json + @report["data"]["exception"]["backtrace"].should == Chef::JSONCompat.to_json(@backtrace) end it "includes the error inspector output in the event data" do @@ -701,7 +701,7 @@ describe Chef::ResourceReporter do }) data_stream = Zlib::GzipReader.new(StringIO.new(data)) data = data_stream.read - data.should eq(@expected_data.to_json) + data.should eq(Chef::JSONCompat.to_json(@expected_data)) response end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 70941e4e82..d10f3ca27b 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -336,6 +336,10 @@ describe Chef::Resource do json.should =~ /json_class/ json.should =~ /instance_vars/ end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @resource } + end end describe "to_hash" do @@ -354,7 +358,7 @@ describe Chef::Resource do describe "self.json_create" do it "should deserialize itself from json" do - json = @resource.to_json + json = Chef::JSONCompat.to_json(@resource) serialized_node = Chef::JSONCompat.from_json(json) serialized_node.should be_a_kind_of(Chef::Resource) serialized_node.name.should eql(@resource.name) diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb index 05ebf282db..42819cda21 100644 --- a/spec/unit/role_spec.rb +++ b/spec/unit/role_spec.rb @@ -215,6 +215,10 @@ describe Chef::Role do end end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @role } + end end describe "when created from JSON", :json => true do diff --git a/spec/unit/run_list_spec.rb b/spec/unit/run_list_spec.rb index 220e4ea4a6..d2f0e01811 100644 --- a/spec/unit/run_list_spec.rb +++ b/spec/unit/run_list_spec.rb @@ -304,7 +304,11 @@ describe Chef::RunList do end it "converts to json by converting its array form" do - @run_list.to_json.should == ["recipe[nagios::client]", "role[production]", "recipe[apache2]"].to_json + Chef::JSONCompat.to_json(@run_list).should == Chef::JSONCompat.to_json(["recipe[nagios::client]", "role[production]", "recipe[apache2]"]) + end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @run_list } end end diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb index 08bde33d7b..055512444b 100644 --- a/spec/unit/user_spec.rb +++ b/spec/unit/user_spec.rb @@ -154,6 +154,10 @@ describe Chef::User do it "does not include the password if not present" do @json.should_not include("password") end + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:subject) { @user } + end end describe "when deserializing from JSON" do @@ -163,7 +167,7 @@ describe Chef::User do "private_key" => "pandas", "password" => "password", "admin" => true } - @user = Chef::User.from_json(user.to_json) + @user = Chef::User.from_json(Chef::JSONCompat.to_json(user)) end it "should deserialize to a Chef::User object" do |