#
# Author:: Matthew Kent (<mkent@magoazul.com>)
# 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"

describe Ohai::System, "Linux filesystem plugin" do
  let(:plugin) { get_plugin("filesystem") }

  before do
    allow(plugin).to receive(:collect_os).and_return(:linux)

    allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, "", ""))
    allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, "", ""))
    allow(plugin).to receive(:shell_out).with("mount").and_return(mock_shell_out(0, "", ""))
    allow(plugin).to receive(:which).with("lsblk").and_return(nil)
    allow(plugin).to receive(:which).with("df").and_return("/bin/df")
    allow(plugin).to receive(:which).with("mount").and_return("/bin/mount")
    allow(plugin).to receive(:which).with("blkid").and_return("/sbin/blkid")
    allow(plugin).to receive(:shell_out).with("/sbin/blkid", timeout: 60).and_return(mock_shell_out(0, "", ""))

    allow(plugin).to receive(:shell_out)
      .with("lsblk -n -P -o NAME,UUID,LABEL,FSTYPE", timeout: 60)
      .and_return(mock_shell_out(0, "", ""))

    allow(File).to receive(:exist?).with("/proc/mounts").and_return(false)

    %w{sdb1 sdb2 sda1 sda2 md0 md1 md2}.each do |name|
      allow(File).to receive(:exist?).with("/dev/#{name}").and_return(true)
    end
    %w{
       sys.vg-root.lv
       sys.vg-swap.lv
       sys.vg-tmp.lv
       sys.vg-usr.lv
       sys.vg-var.lv
       sys.vg-home.lv
       debian--7-root
    }.each do |name|
      allow(File).to receive(:exist?).with("/dev/#{name}").and_return(false)
      allow(File).to receive(:exist?).with("/dev/mapper/#{name}").and_return(true)
    end

    BTRFS_ALLOC = {
      "data" => {
        "total_bytes" => "10000000000",
        "bytes_used" => "7000000000",
      },
      "metadata" => {
        "total_bytes" => "2000000000",
        "bytes_used" => "200000000",
      },
      "system" => {
        "total_bytes" => "100000000",
        "bytes_used" => "10000",
      },
    }.freeze

    btrfs_sysfs_base = "/sys/fs/btrfs/d6efda02-1b73-453c-8c74-7d8dee78fa5e/allocation"
    %w{data metadata system}.each do |bg_type|
      allow(Dir).to receive(:exist?).with(btrfs_sysfs_base).and_return(true)
      allow(File).to receive(:exist?).with("#{btrfs_sysfs_base}/#{bg_type}/single").and_return(true)
      allow(File).to receive(:exist?).with("#{btrfs_sysfs_base}/#{bg_type}/dup").and_return(false)
      %w{total_bytes bytes_used}.each do |field|
        allow(plugin).to receive(:file_read).with("#{btrfs_sysfs_base}/#{bg_type}/#{field}").and_return(BTRFS_ALLOC[bg_type][field])
      end
    end
  end

  describe "when gathering filesystem usage data from df" do
    before do
      @stdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/mapper/sys.vg-special.lv  97605057  53563253  44041805      56% /special
        /dev/mapper/sys.vg-tmp.lv   1919048     46588   1774976       3% /tmp
        /dev/mapper/sys.vg-usr.lv  19223252   5479072  12767696      31% /usr
        /dev/mapper/sys.vg-var.lv  19223252   3436556  14810212      19% /var
        /dev/md0                960492     36388    875312       4% /boot
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @stdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/xvda1     1310720 107407 1203313    9% /
        /dev/mapper/sys.vg-special.lv            124865    380  124485    1% /special
        tmpfs           126922    273  126649    1% /run
        none            126922      1  126921    1% /run/lock
        none            126922      1  126921    1% /run/shm
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))
    end

    it "runs df -P and df -iP" do
      expect(plugin).to receive(:shell_out).ordered.with("df -P").and_return(mock_shell_out(0, @stdout, ""))
      expect(plugin).to receive(:shell_out).ordered.with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))
      plugin.run
    end

    it "sets kb_size to value from df -P" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:kb_size]).to eq("97605057")
    end

    it "sets kb_used to value from df -P" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:kb_used]).to eq("53563253")
    end

    it "sets kb_available to value from df -P" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:kb_available]).to eq("44041805")
    end

    it "sets percent_used to value from df -P" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:percent_used]).to eq("56%")
    end

    it "sets mount to value from df -P" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:mount]).to eq("/special")
    end

    it "sets total_inodes to value from df -iP" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:total_inodes]).to eq("124865")
    end

    it "sets inodes_used to value from df -iP" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:inodes_used]).to eq("380")
    end

    it "sets inodes_available to value from df -iP" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:inodes_available]).to eq("124485")
    end
  end

  describe "when gathering mounted filesystem data from mount" do
    before do
      @stdout = <<~MOUNT
        /dev/mapper/sys.vg-root.lv on / type ext4 (rw,noatime,errors=remount-ro)
        tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
        proc on /proc type proc (rw,noexec,nosuid,nodev)
        sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
        udev on /dev type tmpfs (rw,mode=0755)
        tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
        devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
        /dev/mapper/sys.vg-home.lv on /home type btrfs (rw,noatime)
        /dev/mapper/sys.vg-special.lv on /special type btrfs (ro,noatime)
        /dev/mapper/sys.vg-tmp.lv on /tmp type ext4 (rw,noatime)
        /dev/mapper/sys.vg-usr.lv on /usr type ext4 (rw,noatime)
        /dev/mapper/sys.vg-var.lv on /var type ext4 (rw,noatime)
        /dev/md0 on /boot type ext3 (rw,noatime,errors=remount-ro)
        fusectl on /sys/fs/fuse/connections type fusectl (rw)
        binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
      MOUNT
      allow(plugin).to receive(:shell_out).with("mount").and_return(mock_shell_out(0, @stdout, ""))
    end

    it "runs mount" do
      expect(plugin).to receive(:shell_out).with("mount").and_return(mock_shell_out(0, @stdout, ""))
      plugin.run
    end

    it "sets mount to value from mount" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:mount]).to eq("/special")
    end

    it "sets fs_type to value from mount" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:fs_type]).to eq("btrfs")
    end

    it "sets mount_options to an array of values from mount" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:mount_options]).to eq(%w{ro noatime})
    end
  end

  describe "when gathering filesystem type data from blkid" do
    before do
      # blkid and lsblk output are coorelated with df/mount output, so the
      # most full test of them actually requires we have both
      @dfstdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/mapper/sys.vg-special.lv  97605057  53563253  44041805      56% /special
        /dev/mapper/sys.vg-tmp.lv   1919048     46588   1774976       3% /tmp
        /dev/mapper/sys.vg-usr.lv  19223252   5479072  12767696      31% /usr
        /dev/mapper/sys.vg-var.lv  19223252   3436556  14810212      19% /var
        /dev/md0                960492     36388    875312       4% /boot
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @dfstdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/xvda1     1310720 107407 1203313    9% /
        /dev/mapper/sys.vg-special.lv            124865    380  124485    1% /special
        tmpfs           126922    273  126649    1% /run
        none            126922      1  126921    1% /run/lock
        none            126922      1  126921    1% /run/shm
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))

      @stdout = <<~BLKID_TYPE
        /dev/sdb1: LABEL="fuego:0" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" TYPE="linux_raid_member"
        /dev/sdb2: LABEL="fuego:1" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" TYPE="linux_raid_member"
        /dev/sda1: LABEL="fuego:0" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" TYPE="linux_raid_member"
        /dev/sda2: LABEL="fuego:1" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" TYPE="linux_raid_member"
        /dev/md0: LABEL="/boot" UUID="37b8de8e-0fe3-4b5a-b9b4-dde33e19bb32" TYPE="ext3"
        /dev/md1: UUID="YsIe0R-fj1y-LXTd-imla-opKo-OuIe-TBoxSK" TYPE="LVM2_member"
        /dev/mapper/sys.vg-root.lv: LABEL="/" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" TYPE="ext4"
        /dev/mapper/sys.vg-swap.lv: UUID="9bc2e515-8ddc-41c3-9f63-4eaebde9ce96"  TYPE="swap"
        /dev/mapper/sys.vg-tmp.lv: LABEL="/tmp" UUID="74cf7eb9-428f-479e-9a4a-9943401e81e5" TYPE="ext4"
        /dev/mapper/sys.vg-usr.lv: LABEL="/usr" UUID="26ec33c5-d00b-4f88-a550-492def013bbc" TYPE="ext4"
        /dev/mapper/sys.vg-var.lv: LABEL="/var" UUID="6b559c35-7847-4ae2-b512-c99012d3f5b3" TYPE="ext4"
        /dev/mapper/sys.vg-home.lv: LABEL="/home" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" TYPE="btrfs"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out).with("/sbin/blkid", timeout: 60).and_return(mock_shell_out(0, @stdout, ""))
    end

    it "runs blkid" do
      plugin.run
    end

    it "sets kb_size to value from blkid" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/md1,"][:fs_type]).to eq("LVM2_member")
      expect(plugin[:filesystem]["by_pair"]["/dev/sda2,"][:uuid]).to eq("e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa")
      expect(plugin[:filesystem]["by_pair"]["/dev/md0,/boot"][:label]).to eq("/boot")
    end

    it "collects btrfs data by uuid" do
      plugin.run
      expect(plugin[:filesystem]["by_mountpoint"]["/home"][:btrfs]["allocation"]).to eq(BTRFS_ALLOC)
    end
  end

  describe "when gathering filesystem type data from lsblk" do
    before do
      @dfstdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/mapper/sys.vg-special.lv  97605057  53563253  44041805      56% /special
        /dev/mapper/sys.vg-tmp.lv   1919048     46588   1774976       3% /tmp
        /dev/mapper/sys.vg-usr.lv  19223252   5479072  12767696      31% /usr
        /dev/mapper/sys.vg-var.lv  19223252   3436556  14810212      19% /var
        /dev/md0                960492     36388    875312       4% /boot
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @dfstdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/xvda1     1310720 107407 1203313    9% /
        /dev/mapper/sys.vg-special.lv            124865    380  124485    1% /special
        tmpfs           126922    273  126649    1% /run
        none            126922      1  126921    1% /run/lock
        none            126922      1  126921    1% /run/shm
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))

      allow(plugin).to receive(:which).with("lsblk").and_return("/sbin/lsblk")
      allow(plugin).to receive(:which).with("blkid").and_return(nil)
      @stdout = <<~BLKID_TYPE
        NAME="sdb1" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" LABEL="fuego:0" FSTYPE="LVM2_member"
        NAME="sdb2" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" LABEL="fuego:1" FSTYPE="LVM2_member"
        NAME="sda1" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" LABEL="fuego:0" FSTYPE="LVM2_member"
        NAME="sda2" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" LABEL="fuego:1" FSTYPE="LVM2_member"
        NAME="md0" UUID="37b8de8e-0fe3-4b5a-b9b4-dde33e19bb32" LABEL="/boot" FSTYPE="ext3"
        NAME="md1" UUID="YsIe0R-fj1y-LXTd-imla-opKo-OuIe-TBoxSK" LABEL="" FSTYPE="LVM2_member"
        NAME="sys.vg-root.lv" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" LABEL="/" FSTYPE="ext4"
        NAME="sys.vg-swap.lv" UUID="9bc2e515-8ddc-41c3-9f63-4eaebde9ce96" LABEL="" FSTYPE="swap"
        NAME="sys.vg-tmp.lv" UUID="74cf7eb9-428f-479e-9a4a-9943401e81e5" LABEL="/tmp" FSTYPE="ext4"
        NAME="sys.vg-usr.lv" UUID="26ec33c5-d00b-4f88-a550-492def013bbc" LABEL="/usr" FSTYPE="ext4"
        NAME="sys.vg-var.lv" UUID="6b559c35-7847-4ae2-b512-c99012d3f5b3" LABEL="/var" FSTYPE="ext4"
        NAME="sys.vg-home.lv" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" LABEL="/home" FSTYPE="btrfs"
        NAME="debian--7-root (dm-0)" UUID="09187faa-3512-4505-81af-7e86d2ccb99a" LABEL="root" FSTYPE="ext4"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out)
        .with("/sbin/lsblk -n -P -o NAME,UUID,LABEL,FSTYPE", timeout: 60)
        .and_return(mock_shell_out(0, @stdout, ""))
    end

    it "runs lsblk -n -P -o NAME,UUID,LABEL,FSTYPE" do
      plugin.run
    end

    it "sets kb_size to value from lsblk -n -P -o NAME,UUID,LABEL,FSTYPE" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/md1,"][:fs_type]).to eq("LVM2_member")
      expect(plugin[:filesystem]["by_pair"]["/dev/sda2,"][:uuid]).to eq("e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa")
      expect(plugin[:filesystem]["by_pair"]["/dev/md0,/boot"][:label]).to eq("/boot")
    end

    it "ignores extra info in name and set label to value from lsblk -n -P -o NAME,UUID,LABEL,FSTYPE" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/debian--7-root,"][:label]).to eq("root")
    end

  end

  describe "when gathering filesystem type data from both lsblk and blkid" do
    before do
      @dfstdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/mapper/sys.vg-special.lv  97605057  53563253  44041805      56% /special
        /dev/mapper/sys.vg-tmp.lv   1919048     46588   1774976       3% /tmp
        /dev/mapper/sys.vg-usr.lv  19223252   5479072  12767696      31% /usr
        /dev/mapper/sys.vg-var.lv  19223252   3436556  14810212      19% /var
        /dev/md0                960492     36388    875312       4% /boot
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @dfstdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/xvda1     1310720 107407 1203313    9% /
        /dev/mapper/sys.vg-special.lv            124865    380  124485    1% /special
        tmpfs           126922    273  126649    1% /run
        none            126922      1  126921    1% /run/lock
        none            126922      1  126921    1% /run/shm
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))

      allow(plugin).to receive(:which).with("lsblk").and_return("/sbin/lsblk")
      allow(plugin).to receive(:which).with("blkid").and_return("/sbin/blkid")
      @stdout = <<~BLKID_TYPE
        NAME="sdb1" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" LABEL="fuego:0" FSTYPE="LVM2_member"
        NAME="sdb2" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" LABEL="fuego:1" FSTYPE="LVM2_member"
        NAME="sda1" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" LABEL="fuego:0" FSTYPE="LVM2_member"
        NAME="sda2" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" LABEL="fuego:1" FSTYPE="LVM2_member"
        NAME="md0" UUID="37b8de8e-0fe3-4b5a-b9b4-dde33e19bb32" LABEL="/boot" FSTYPE="ext3"
        NAME="md1" UUID="YsIe0R-fj1y-LXTd-imla-opKo-OuIe-TBoxSK" LABEL="" FSTYPE="LVM2_member"
        NAME="sys.vg-root.lv" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" LABEL="/"
        NAME="sys.vg-swap.lv" UUID="9bc2e515-8ddc-41c3-9f63-4eaebde9ce96" LABEL="" FSTYPE="swap"
        NAME="sys.vg-tmp.lv" UUID="74cf7eb9-428f-479e-9a4a-9943401e81e5" LABEL="/tmp" FSTYPE="ext4"
        NAME="sys.vg-usr.lv" UUID="26ec33c5-d00b-4f88-a550-492def013bbc" LABEL="/usr"
        NAME="sys.vg-var.lv" UUID="6b559c35-7847-4ae2-b512-c99012d3f5b3" LABEL="/var" FSTYPE="ext4"
        NAME="sys.vg-home.lv" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" LABEL="/BADhome" FSTYPE="btrfs"
        NAME="debian--7-root (dm-0)" UUID="09187faa-3512-4505-81af-7e86d2ccb99a" LABEL="root" FSTYPE="ext4"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out)
        .with("/sbin/lsblk -n -P -o NAME,UUID,LABEL,FSTYPE", timeout: 60)
        .and_return(mock_shell_out(0, @stdout, ""))
      @stdout = <<~BLKID_TYPE
        /dev/sdb1: LABEL="fuego:0" TYPE="linux_raid_member"
        /dev/sdb2: LABEL="fuego:1" TYPE="linux_raid_member"
        /dev/sda1: LABEL="fuego:0" UUID="bd1197e0-6997-1f3a-e27e-7801388308b5" TYPE="linux_raid_member"
        /dev/sda2: LABEL="fuego:1" UUID="e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa" TYPE="linux_raid_member"
        /dev/md0: LABEL="/boot" UUID="37b8de8e-0fe3-4b5a-b9b4-dde33e19bb32" TYPE="ext3"
        /dev/md1: UUID="YsIe0R-fj1y-LXTd-imla-opKo-OuIe-TBoxSK" TYPE="LVM2_member"
        /dev/mapper/sys.vg-root.lv: LABEL="/" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" TYPE="ext4"
        /dev/mapper/sys.vg-swap.lv: UUID="9bc2e515-8ddc-41c3-9f63-4eaebde9ce96"  TYPE="swap"
        /dev/mapper/sys.vg-tmp.lv: LABEL="/tmp" UUID="74cf7eb9-428f-479e-9a4a-9943401e81e5" TYPE="ext4"
        /dev/mapper/sys.vg-usr.lv: LABEL="/usr" UUID="26ec33c5-d00b-4f88-a550-492def013bbc" TYPE="ext4"
        /dev/mapper/sys.vg-var.lv: LABEL="/var" UUID="6b559c35-7847-4ae2-b512-c99012d3f5b3" TYPE="ext4"
        /dev/mapper/sys.vg-home.lv: LABEL="/home" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" TYPE="btrfs"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out).with("/sbin/blkid", timeout: 60).and_return(mock_shell_out(0, @stdout, ""))
    end

    it "fills in missing FS data from lsblk using blkid" do
      plugin.run
      pairs = plugin[:filesystem]["by_pair"]
      expect(pairs["/dev/mapper/sys.vg-root.lv,/"]["fs_type"]).to eq("ext4")
      expect(pairs["/dev/mapper/sys.vg-usr.lv,/usr"]["fs_type"]).to eq("ext4")
    end

    it "fills in missing FS data from blkid using lsblk" do
      plugin.run
      pairs = plugin[:filesystem]["by_pair"]
      expect(pairs["/dev/sdb1,"]["uuid"]).to eq("bd1197e0-6997-1f3a-e27e-7801388308b5")
      expect(pairs["/dev/sdb2,"]["uuid"]).to eq("e36d933e-e5b9-cfe5-6845-1f84d0f7fbfa")
    end

    it "prefers lsblk data to blkid data when they conflict" do
      plugin.run
      pairs = plugin[:filesystem]["by_pair"]
      expect(pairs["/dev/mapper/sys.vg-home.lv,/home"]["label"]).to eq("/home")
    end

  end

  describe "when gathering data from /proc/mounts" do
    before do
      allow(File).to receive(:exist?).with("/proc/mounts").and_return(true)
      @double_file = double("/proc/mounts")
      @mounts = <<~MOUNTS
        rootfs / rootfs rw 0 0
        none /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
        none /proc proc rw,nosuid,nodev,noexec,relatime 0 0
        none /dev devtmpfs rw,relatime,size=2025576k,nr_inodes=506394,mode=755 0 0
        none /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
        /dev/mapper/sys.vg-root.lv / ext4 rw,noatime,errors=remount-ro,barrier=1,data=ordered 0 0
        tmpfs /lib/init/rw tmpfs rw,nosuid,relatime,mode=755 0 0
        tmpfs /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0
        /dev/mapper/sys.vg-home.lv /home btrfs rw,noatime,attr2,noquota 0 0
        /dev/mapper/sys.vg-special.lv /special btrfs ro,noatime,attr2,noquota 0 0
        /dev/mapper/sys.vg-tmp.lv /tmp ext4 rw,noatime,barrier=1,data=ordered 0 0
        /dev/mapper/sys.vg-usr.lv /usr ext4 rw,noatime,barrier=1,data=ordered 0 0
        /dev/mapper/sys.vg-var.lv /var ext4 rw,noatime,barrier=1,data=ordered 0 0
        /dev/md0 /boot ext3 rw,noatime,errors=remount-ro,data=ordered 0 0
        fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0
        binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,nosuid,nodev,noexec,relatime 0 0
      MOUNTS
      @counter = 0
      allow(@double_file).to receive(:read_nonblock) do
        @counter += 1
        raise EOFError if @counter == 2

        @mounts
      end
      allow(@double_file).to receive(:close)
      allow(File).to receive(:open).with("/proc/mounts").and_return(@double_file)
    end

    it "sets mount to value from /proc/mounts" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:mount]).to eq("/special")
    end

    it "sets fs_type to value from /proc/mounts" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:fs_type]).to eq("btrfs")
    end

    it "sets mount_options to an array of values from /proc/mounts" do
      plugin.run
      expect(plugin[:filesystem]["by_pair"]["/dev/mapper/sys.vg-special.lv,/special"][:mount_options]).to eq(%w{ro noatime attr2 noquota})
    end
  end

  describe "when gathering filesystem data with devices mounted more than once" do
    before do
      # there's a few different examples one can run into in this output:
      # 1. A device physically mounted in more than one place: /home and /home2
      # 2. A bind-mounted directory, which shows up as the same device in a
      # subdir: / and /var/chroot
      # 3. tmpfs in multiple places.
      @dfstdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home2
        /dev/mapper/sys.vg-root.lv  4805760    378716   4182924       9% /var/chroot
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @dfstdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/mapper/sys.vg-root.lv     1310720 107407 1203313    9% /
        tmpfs           126922    273  126649    1% /lib/init/rw
        none            126922      1  126921    1% /dev/shm
        udev            126922      1  126921    1% /dev
        /dev/mapper/sys.vg-home.lv  60891136  4696030 56195106      8% /home
        /dev/mapper/sys.vg-home.lv  60891136  4696030 56195106      8% /home2
        /dev/mapper/sys.vg-root.lv  1310720 107407 1203313       9% /var/chroot
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))

      allow(plugin).to receive(:which).with("lsblk").and_return("/sbin/lsblk")
      allow(plugin).to receive(:which).with("blkid").and_return(nil)
      @stdout = <<~BLKID_TYPE
        NAME="/dev/mapper/sys.vg-root.lv" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" LABEL="/" FSTYPE="ext4"
        NAME="/dev/mapper/sys.vg-home.lv" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" LABEL="/home" FSTYPE="btrfs"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out)
        .with("/sbin/lsblk -n -P -o NAME,UUID,LABEL,FSTYPE", timeout: 60)
        .and_return(mock_shell_out(0, @stdout, ""))
    end

    it "provides a devices view with all mountpoints" do
      plugin.run
      expect(plugin[:filesystem]["by_device"]["/dev/mapper/sys.vg-root.lv"][:mounts]).to eq(["/", "/var/chroot"])
      expect(plugin[:filesystem]["by_device"]["/dev/mapper/sys.vg-home.lv"][:mounts]).to eq(["/home", "/home2"])
      expect(plugin[:filesystem]["by_device"]["tmpfs"][:mounts]).to eq(["/lib/init/rw", "/dev/shm"])
    end
  end

  describe "when gathering filesystem data with double-mounts" do
    before do
      @dfstdout = <<~DF
        Filesystem         1024-blocks      Used Available Capacity Mounted on
        /dev/mapper/sys.vg-root.lv   4805760    378716   4182924       9% /
        tmpfs                  2030944         0   2030944       0% /lib/init/rw
        udev                   2025576       228   2025348       1% /dev
        tmpfs                  2030944      2960   2027984       1% /dev/shm
        /dev/mapper/sys.vg-home.lv  97605056  53563252  44041804      55% /home
        /dev/sdb1              97605056  53563252  44041804      55% /mnt
        /dev/sdc1              4805760    378716   4182924       9% /mnt
      DF
      allow(plugin).to receive(:shell_out).with("df -P").and_return(mock_shell_out(0, @dfstdout, ""))

      @inode_stdout = <<~DFI
        Filesystem      Inodes  IUsed   IFree IUse% Mounted on
        /dev/mapper/sys.vg-root.lv     1310720 107407 1203313    9% /
        tmpfs           126922    273  126649    1% /lib/init/rw
        none            126922      1  126921    1% /dev/shm
        udev            126922      1  126921    1% /dev
        /dev/mapper/sys.vg-home.lv  60891136  4696030 56195106      8% /home
        /dev/sdb1       60891136  4696030 56195106      8% /mnt
        /dev/sdc1       1310720 107407 1203313          9% /mnt
      DFI
      allow(plugin).to receive(:shell_out).with("df -iP").and_return(mock_shell_out(0, @inode_stdout, ""))

      allow(plugin).to receive(:which).with("lsblk").and_return("/sbin/lsblk")
      allow(plugin).to receive(:which).with("blkid").and_return(nil)
      @stdout = <<~BLKID_TYPE
        NAME="/dev/mapper/sys.vg-root.lv" UUID="7742d14b-80a3-4e97-9a32-478be9ea9aea" LABEL="/" FSTYPE="ext4"
        NAME="/dev/sdb1" UUID="6b559c35-7847-4ae2-b512-c99012d3f5b3" LABEL="/mnt" FSTYPE="ext4"
        NAME="/dev/sdc1" UUID="7f1e51bf-3608-4351-b7cd-379e39cff36a" LABEL="/mnt" FSTYPE="ext4"
        NAME="/dev/mapper/sys.vg-home.lv" UUID="d6efda02-1b73-453c-8c74-7d8dee78fa5e" LABEL="/home" FSTYPE="btrfs"
      BLKID_TYPE
      allow(plugin).to receive(:shell_out)
        .with("/sbin/lsblk -n -P -o NAME,UUID,LABEL,FSTYPE", timeout: 60)
        .and_return(mock_shell_out(0, @stdout, ""))
    end

    it "provides a mounts view with all devices" do
      plugin.run
      expect(plugin[:filesystem]["by_mountpoint"]["/mnt"][:devices]).to eq(["/dev/sdb1", "/dev/sdc1"])
    end
  end

  %w{df mount}.each do |command|
    describe "when :allow_partial_data set, #{command} does not exist" do
      before do
        Ohai.config[:plugin][:filesystem][:allow_partial_data] = true
      end

      after do
        Ohai.config[:plugin][:filesystem][:allow_partial_data] = false
      end

      it "logs warning about #{command} missing" do
        Ohai.config[:plugin][:filesystem][:allow_partial_data] = true
        allow(plugin).to receive(:shell_out).with(/#{command}/).and_raise(Ohai::Exceptions::Exec)
        expect_any_instance_of(Mixlib::Log::Child).to receive(:warn).with("Plugin Filesystem: #{command} binary is not available. Some data will not be available.")
        plugin.run
      end
    end
  end
end
