File Manager
Viewing File: data_bag_item_spec.rb
#
# Author:: Adam Jacob (<adam@chef.io>)
# Copyright:: Copyright 2008-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "spec_helper"
require "chef/data_bag_item"
describe Chef::DataBagItem do
let(:data_bag_item) { Chef::DataBagItem.new }
describe "initialize" do
it "should be a Chef::DataBagItem" do
expect(data_bag_item).to be_a_kind_of(Chef::DataBagItem)
end
end
describe "data_bag" do
it "should let you set the data_bag to a string" do
expect(data_bag_item.data_bag("clowns")).to eq("clowns")
end
it "should return the current data_bag type" do
data_bag_item.data_bag "clowns"
expect(data_bag_item.data_bag).to eq("clowns")
end
it "should not accept spaces" do
expect { data_bag_item.data_bag "clown masters" }.to raise_error(ArgumentError)
end
it "should throw an ArgumentError if you feed it anything but a string" do
expect { data_bag_item.data_bag Hash.new }.to raise_error(ArgumentError)
end
end
describe "raw_data" do
it "should let you set the raw_data with a hash" do
expect { data_bag_item.raw_data = { "id" => "octahedron" } }.not_to raise_error
end
it "should let you set the raw_data from a mash" do
expect { data_bag_item.raw_data = Mash.new({ "id" => "octahedron" }) }.not_to raise_error
end
it "should raise an exception if you set the raw data without a key" do
expect { data_bag_item.raw_data = { "monkey" => "pants" } }.to raise_error(ArgumentError)
end
it "should raise an exception if you set the raw data to something other than a hash" do
expect { data_bag_item.raw_data = "katie rules" }.to raise_error(ArgumentError)
end
it "should accept alphanum/-/_ for the id" do
expect { data_bag_item.raw_data = { "id" => "h1-_" } }.not_to raise_error
end
it "should accept alphanum.alphanum for the id" do
expect { data_bag_item.raw_data = { "id" => "foo.bar" } }.not_to raise_error
end
it "should accept .alphanum for the id" do
expect { data_bag_item.raw_data = { "id" => ".bozo" } }.not_to raise_error
end
it "should raise an exception if the id contains anything but alphanum/-/_" do
expect { data_bag_item.raw_data = { "id" => "!@#" } }.to raise_error(ArgumentError)
end
it "should return the raw data" do
data_bag_item.raw_data = { "id" => "highway_of_emptiness" }
expect(data_bag_item.raw_data).to eq({ "id" => "highway_of_emptiness" })
end
it "should be a Mash by default" do
expect(data_bag_item.raw_data).to be_a_kind_of(Mash)
end
end
describe "object_name" do
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("dreams")
data_bag_item.raw_data = { "id" => "the_beatdown" }
data_bag_item
end
it "should return an object name based on the bag name and the raw_data id" do
expect(data_bag_item.object_name).to eq("data_bag_item_dreams_the_beatdown")
end
end
describe "class method object_name" do
it "should return an object name based based on the bag name and an id" do
expect(Chef::DataBagItem.object_name("zen", "master")).to eq("data_bag_item_zen_master")
end
end
describe "class method name" do
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("dreams")
data_bag_item.raw_data = { "id" => "the_beatdown", "name" => "Bruce" }
data_bag_item
end
it "should return the object name" do
expect(data_bag_item.name).to eq(data_bag_item.object_name)
end
it "should be distinct from raw_data 'name' key" do
expect(data_bag_item["name"]).to eq("Bruce")
expect(data_bag_item["name"]).not_to eq(data_bag_item.object_name)
end
end
describe "when used like a Hash" do
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" }
data_bag_item
end
it "responds to keys" do
expect(data_bag_item.keys).to include("id")
expect(data_bag_item.keys).to include("trials")
end
it "supports element reference with []" do
expect(data_bag_item["id"]).to eq("journey")
end
it "implements all the methods of Hash" do
methods = [:rehash, :to_hash, :[], :fetch, :[]=, :store, :default,
:default=, :default_proc, :index, :size, :length,
:empty?, :each_value, :each_key, :each_pair, :each, :keys, :values,
:values_at, :delete, :delete_if, :reject!, :clear,
:invert, :update, :replace, :merge!, :merge, :has_key?, :has_value?,
:key?, :value?]
methods.each do |m|
expect(data_bag_item).to respond_to(m)
end
end
end
describe "from_hash" do
context "when hash contains raw_data" do
let(:data_bag_item) do
Chef::DataBagItem.from_hash({ "raw_data" => { "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" } })
end
it "should have the id key set" do
expect(data_bag_item["id"]).to eq("whoa")
end
it "should have the name key set" do
expect(data_bag_item["name"]).to eq("Bruce")
end
end
context "when hash does not contain raw_data" do
let(:data_bag_item) do
Chef::DataBagItem.from_hash({ "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" })
end
it "should have the id key set" do
expect(data_bag_item["id"]).to eq("whoa")
end
it "should have the name key set" do
expect(data_bag_item["name"]).to eq("Bruce")
end
end
end
describe "to_hash" do
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("still_lost")
data_bag_item.raw_data = { "id" => "whoa", "name" => "Bruce", "i_know" => "kung_fu" }
data_bag_item
end
let!(:original_data_bag_keys) { data_bag_item.keys }
let(:to_hash) { data_bag_item.to_hash }
it "should return a hash" do
expect(to_hash).to be_a_kind_of(Hash)
end
it "should have the raw_data keys as top level keys" do
expect(to_hash["id"]).to eq("whoa")
expect(to_hash["name"]).to eq("Bruce")
expect(to_hash["i_know"]).to eq("kung_fu")
end
it "should have the chef_type of data_bag_item" do
expect(to_hash["chef_type"]).to eq("data_bag_item")
end
it "should have the data_bag set" do
expect(to_hash["data_bag"]).to eq("still_lost")
end
it "should not mutate the data_bag_item" do
data_bag_item.to_hash
expect(data_bag_item.keys).to eq(original_data_bag_keys)
end
end
describe "when deserializing from JSON" do
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("mars_volta")
data_bag_item.raw_data = { "id" => "octahedron", "name" => "Bruce", "snooze" => { "finally" => :world_will } }
data_bag_item
end
let(:deserial) { Chef::DataBagItem.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(data_bag_item))) }
it "should deserialize to a Chef::DataBagItem object" do
expect(deserial).to be_a_kind_of(Chef::DataBagItem)
end
it "should have a matching 'data_bag' value" do
expect(deserial.data_bag).to eq(data_bag_item.data_bag)
end
it "should have a matching 'id' key" do
expect(deserial["id"]).to eq("octahedron")
end
it "should have a matching 'name' key" do
expect(deserial["name"]).to eq("Bruce")
end
it "should have a matching 'snooze' key" do
expect(deserial["snooze"]).to eq({ "finally" => "world_will" })
end
include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
let(:jsonable) { data_bag_item }
end
end
describe "when converting to a string" do
it "converts to a string in the form data_bag_item[ID]" do
data_bag_item["id"] = "heart of darkness"
expect(data_bag_item.to_s).to eq("data_bag_item[heart of darkness]")
end
it "inspects as data_bag_item[BAG, ID, RAW_DATA]" do
raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
data_bag_item.raw_data = raw_data
data_bag_item.data_bag("books")
expect(data_bag_item.inspect).to eq("data_bag_item[\"books\", \"heart_of_darkness\", #{raw_data.inspect}]")
end
end
describe "save" do
let(:server) { instance_double(Chef::ServerAPI) }
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item["id"] = "heart of darkness"
data_bag_item.raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
data_bag_item.data_bag("books")
data_bag_item
end
before do
expect(Chef::ServerAPI).to receive(:new).and_return(server)
end
it "should update the item when it already exists" do
expect(server).to receive(:put).with("data/books/heart_of_darkness", data_bag_item)
data_bag_item.save
end
it "should create if the item is not found" do
exception = double("404 error", :code => "404")
expect(server).to receive(:put).and_raise(Net::HTTPServerException.new("foo", exception))
expect(server).to receive(:post).with("data/books", data_bag_item)
data_bag_item.save
end
describe "when whyrun mode is enabled" do
before do
Chef::Config[:why_run] = true
end
after do
Chef::Config[:why_run] = false
end
it "should not save" do
expect(server).not_to receive(:put)
expect(server).not_to receive(:post)
data_bag_item.data_bag("books")
data_bag_item.save
end
end
end
describe "destroy" do
let(:server) { instance_double(Chef::ServerAPI) }
let(:data_bag_item) do
data_bag_item = Chef::DataBagItem.new
data_bag_item.data_bag("a_baggy_bag")
data_bag_item.raw_data = { "id" => "some_id" }
data_bag_item
end
it "should set default parameters" do
expect(Chef::ServerAPI).to receive(:new).and_return(server)
expect(server).to receive(:delete).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id")
data_bag_item.destroy
end
end
describe "when loading" do
before do
data_bag_item.raw_data = { "id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2} }
data_bag_item.data_bag("users")
end
describe "from an API call" do
let(:http_client) { double("Chef::ServerAPI") }
before do
allow(Chef::ServerAPI).to receive(:new).and_return(http_client)
end
it "converts raw data to a data bag item" do
expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item.to_hash)
item = Chef::DataBagItem.load(:users, "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to eq(data_bag_item)
end
it "does not convert when a DataBagItem is returned from the API call" do
expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item)
item = Chef::DataBagItem.load(:users, "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to equal(data_bag_item)
end
end
describe "in solo mode" do
before do
Chef::Config[:solo_legacy_mode] = true
end
after do
Chef::Config[:solo_legacy_mode] = false
end
it "converts the raw data to a data bag item" do
expect(Chef::DataBag).to receive(:load).with("users").and_return({ "charlie" => data_bag_item.to_hash })
item = Chef::DataBagItem.load("users", "charlie")
expect(item).to be_a_kind_of(Chef::DataBagItem)
expect(item).to eq(data_bag_item)
end
it "raises an exception for unknown items" do
expect(Chef::DataBag).to receive(:load).with("users").and_return({ "charlie" => data_bag_item.to_hash })
expect { Chef::DataBagItem.load("users", "wonka") }.to raise_error Chef::Exceptions::InvalidDataBagItemID
end
end
end
end