\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /opt/chef/embedded/lib/ruby/gems/2.7.0/gems/chef-16.3.45/spec/unit/policy_builder/

Viewing File: dynamic_spec.rb

#
# Author:: Daniel DeLeo (<dan@chef.io>)
# Copyright:: Copyright (c) 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/policy_builder"

describe Chef::PolicyBuilder::Dynamic do

  let(:node_name) { "joe_node" }
  let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
  let(:json_attribs) { { "custom_attr" => "custom_attr_value" } }
  let(:override_runlist) { nil }
  let(:events) { Chef::EventDispatch::Dispatcher.new }

  let(:err_namespace) { Chef::PolicyBuilder::Policyfile }

  let(:base_node) do
    node = Chef::Node.new
    node.name(node_name)
    node
  end

  let(:node) { base_node }

  subject(:policy_builder) { Chef::PolicyBuilder::Dynamic.new(node_name, ohai_data, json_attribs, override_runlist, events) }

  describe "loading policy data" do

    describe "delegating PolicyBuilder API to the correct implementation" do

      let(:implementation) { instance_double("Chef::PolicyBuilder::Policyfile") }

      before do
        allow(policy_builder).to receive(:implementation).and_return(implementation)
      end

      # Dynamic should load_node, figure out the correct backend, then forward
      # messages to it after. That behavior is tested below.
      it "responds to #load_node" do
        expect(policy_builder).to respond_to(:load_node)
      end

      it "forwards #original_runlist" do
        expect(implementation).to receive(:original_runlist)
        policy_builder.original_runlist
      end

      it "forwards #run_context" do
        expect(implementation).to receive(:run_context)
        policy_builder.run_context
      end

      it "forwards #run_list_expansion" do
        expect(implementation).to receive(:run_list_expansion)
        policy_builder.run_list_expansion
      end

      it "forwards #build_node to the implementation object" do
        expect(implementation).to receive(:build_node)
        policy_builder.build_node
      end

      it "forwards #setup_run_context to the implementation object" do
        expect(implementation).to receive(:setup_run_context)
        policy_builder.setup_run_context

        arg = Object.new

        expect(implementation).to receive(:setup_run_context).with(arg)
        policy_builder.setup_run_context(arg)
      end

      it "forwards #expand_run_list to the implementation object" do
        expect(implementation).to receive(:expand_run_list)
        policy_builder.expand_run_list
      end

      it "forwards #sync_cookbooks to the implementation object" do
        expect(implementation).to receive(:sync_cookbooks)
        policy_builder.sync_cookbooks
      end

      it "forwards #temporary_policy? to the implementation object" do
        expect(implementation).to receive(:temporary_policy?)
        policy_builder.temporary_policy?
      end

    end

    describe "selecting a backend implementation" do

      let(:implementation) do
        policy_builder.select_implementation(node)
        policy_builder.implementation
      end

      context "when no policyfile attributes are present on the node" do

        context "and json_attribs are not given" do

          let(:json_attribs) { {} }

          it "uses the ExpandNodeObject implementation" do
            expect(implementation).to be_a(Chef::PolicyBuilder::ExpandNodeObject)
          end

        end

        context "and no policyfile attributes are present in json_attribs" do

          let(:json_attribs) { { "foo" => "bar" } }

          it "uses the ExpandNodeObject implementation" do
            expect(implementation).to be_a(Chef::PolicyBuilder::ExpandNodeObject)
          end

        end

        context "and policy_name and policy_group are set on Chef::Config" do

          before do
            Chef::Config[:policy_name] = "example-policy"
            Chef::Config[:policy_group] = "testing"
          end

          it "uses the Policyfile implementation" do
            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
          end

        end

        context "and deployment_group and policy_document_native_api are set on Chef::Config" do

          before do
            Chef::Config[:deployment_group] = "example-policy-staging"
            Chef::Config[:policy_document_native_api] = false
          end

          it "uses the Policyfile implementation" do
            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
          end

        end

        context "and policyfile attributes are present in json_attribs" do

          let(:json_attribs) { { "policy_name" => "example-policy", "policy_group" => "testing" } }

          it "uses the Policyfile implementation" do
            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
          end

        end

      end

      context "when policyfile attributes are present on the node" do

        let(:node) do
          base_node.policy_name = "example-policy"
          base_node.policy_group = "staging"
          base_node
        end

        it "uses the Policyfile implementation" do
          expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
        end

      end

    end

    describe "loading a node" do

      let(:implementation) { instance_double("Chef::PolicyBuilder::Policyfile") }

      before do
        allow(policy_builder).to receive(:implementation).and_return(implementation)
      end

      context "when not running chef solo" do

        context "when successful" do

          before do
            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
            expect(policy_builder).to receive(:select_implementation).with(node)
            expect(implementation).to receive(:finish_load_node).with(node)
          end

          it "selects the backend implementation and continues node loading" do
            policy_builder.load_node
          end

        end

        context "when an error occurs finding the node" do

          before do
            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_raise("oops")
          end

          it "sends a node_load_failed event and re-raises" do
            expect(events).to receive(:node_load_failed)
            expect { policy_builder.load_node }.to raise_error("oops")
          end

        end

        context "when an error occurs in the implementation's finish_load_node call" do

          before do
            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
            expect(policy_builder).to receive(:select_implementation).with(node)
            expect(implementation).to receive(:finish_load_node).and_raise("oops")
          end

          it "sends a node_load_failed event and re-raises" do
            expect(events).to receive(:node_load_failed)
            expect { policy_builder.load_node }.to raise_error("oops")
          end

        end

      end

      context "when running chef solo" do

        before do
          Chef::Config[:solo_legacy_mode] = true
          expect(Chef::Node).to receive(:build).with(node_name).and_return(node)
          expect(policy_builder).to receive(:select_implementation).with(node)
          expect(implementation).to receive(:finish_load_node).with(node)
        end

        it "selects the backend implementation and continues node loading" do
          policy_builder.load_node
        end

      end

    end

  end

end