#
# Author:: Mike Dodge (<mikedodge04@gmail.com>)
# Copyright:: Copyright (c) 2015 Facebook, 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"

describe Chef::Provider::Launchd do

  context "When launchd manages call.mom.weekly" do
    let(:node) { Chef::Node.new }
    let(:events) { Chef::EventDispatch::Dispatcher.new }
    let(:run_context) { Chef::RunContext.new(node, {}, events) }
    let(:provider) { Chef::Provider::Launchd.new(new_resource, run_context) }

    let(:label) { "call.mom.weekly" }
    let(:new_resource) { Chef::Resource::Launchd.new(label) }
    let!(:current_resource) { Chef::Resource::Launchd.new(label) }
    let(:test_plist) { String.new <<-XML }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
\t<key>Label</key>
\t<string>call.mom.weekly</string>
\t<key>Program</key>
\t<string>/Library/scripts/call_mom.sh</string>
\t<key>StartCalendarInterval</key>
\t<dict>
\t\t<key>Hourly</key>
\t\t<integer>10</integer>
\t\t<key>Weekday</key>
\t\t<integer>7</integer>
\t</dict>
\t<key>TimeOut</key>
\t<integer>300</integer>
</dict>
</plist>
XML

    let(:test_hash) do {
      "Label" => "call.mom.weekly",
      "Program" => "/Library/scripts/call_mom.sh",
      "StartCalendarInterval" => {
        "Hourly" => 10,
        "Weekday" => 7,
      },
      "TimeOut" => 300
    } end

    before(:each) do
      provider.load_current_resource
    end

    it "resource name and label should be call.mom.weekly" do
      expect(new_resource.name).to eql(label)
      expect(new_resource.label).to eql(label)
    end

    def run_resource_setup_for_action(action)
      new_resource.action(action)
      provider.action = action
      provider.load_current_resource
      provider.define_resource_requirements
      provider.process_resource_requirements
    end

    describe "with type is set to" do
      describe "agent" do
        it "path should be /Library/LaunchAgents/call.mom.weekly.plist" do
          new_resource.type "agent"
          expect(provider.gen_path_from_type).
            to eq("/Library/LaunchAgents/call.mom.weekly.plist")
        end
      end
      describe "daemon" do
        it "path should be /Library/LaunchDaemons/call.mom.weekly.plist" do
          expect(provider.gen_path_from_type).
            to eq("/Library/LaunchDaemons/call.mom.weekly.plist")
        end
      end
    end

    describe "with a :create action and" do
      describe "program is passed" do
        it "should produce the test_plist from properties" do
          new_resource.program "/Library/scripts/call_mom.sh"
          new_resource.time_out 300
          new_resource.start_calendar_interval "Hourly" => 10, "Weekday" => 7
          expect(provider.content?).to be_truthy
          expect(provider.content).to eql(test_plist)
        end
      end

      describe "hash is passed" do
        it "should produce the test_plist from the hash" do
          new_resource.hash test_hash
          expect(provider.content?).to be_truthy
          expect(provider.content).to eql(test_plist)
        end
      end
    end

    describe "with an :enable action" do
      describe "and the file has been updated" do
        before(:each) do
          allow(provider).to receive(
            :manage_plist).with(:create).and_return(true)
          allow(provider).to receive(
            :manage_service).with(:restart).and_return(true)
        end

        it "should call manage_service with a :restart action" do
          expect(provider.manage_service(:restart)).to be_truthy
        end

        it "works with action enable" do
          expect(run_resource_setup_for_action(:enable)).to be_truthy
          provider.action_enable
        end
      end

      describe "and the file has not been updated" do
        before(:each) do
          allow(provider).to receive(
            :manage_plist).with(:create).and_return(nil)
          allow(provider).to receive(
            :manage_service).with(:enable).and_return(true)
        end

        it "should call manage_service with a :enable action" do
          expect(provider.manage_service(:enable)).to be_truthy
        end

        it "works with action enable" do
          expect(run_resource_setup_for_action(:enable)).to be_truthy
          provider.action_enable
        end
      end
    end

    describe "with an :delete action" do
      describe "and the ld file is present" do
        before(:each) do
          allow(File).to receive(:exists?).and_return(true)
          allow(provider).to receive(
            :manage_service).with(:disable).and_return(true)
          allow(provider).to receive(
            :manage_plist).with(:delete).and_return(true)
        end

        it "should call manage_service with a :disable action" do
          expect(provider.manage_service(:disable)).to be_truthy
        end

        it "works with action :delete" do
          expect(run_resource_setup_for_action(:delete)).to be_truthy
          provider.action_delete
        end
      end

      describe "and the ld file is not present" do
        before(:each) do
          allow(File).to receive(:exists?).and_return(false)
          allow(provider).to receive(
            :manage_plist).with(:delete).and_return(true)
        end

        it "works with action :delete" do
          expect(run_resource_setup_for_action(:delete)).to be_truthy
          provider.action_delete
        end
      end
    end
  end
end
