aboutsummaryrefslogtreecommitdiff
path: root/spec/unit/provider/cron/filetype_spec.rb
blob: bd579c194bcdacc6f6f1daee2f153b58ae0a1925 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
require 'spec_helper'
require 'puppet/provider/cron/filetype'

# rubocop:disable RSpec/FilePath
describe Puppet::Provider::Cron::FileType do
  shared_examples_for 'crontab provider' do
    let(:cron)         { type.new('no_such_user') }
    let(:crontab)      { File.read(my_fixture(crontab_output)) }
    let(:options)      { { failonfail: true, combine: true } }
    let(:uid)          { 'no_such_user' }
    let(:user_options) { options.merge(uid: uid) }

    it 'exists' do
      expect(type).not_to be_nil
    end

    # make Puppet::Util::SUIDManager return something deterministic, not the
    # uid of the user running the tests, except where overridden below.
    before :each do
      allow(Puppet::Util::SUIDManager).to receive(:uid).and_return 1234
    end

    describe '#read' do
      before(:each) do
        allow(Puppet::Util).to receive(:uid).with(uid).and_return 9000
      end

      it 'runs crontab -l as the target user' do
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-l'], user_options).and_return(Puppet::Util::Execution::ProcessOutput.new(crontab, 0))
        expect(cron.read).to eq(crontab)
      end

      it 'does not switch user if current user is the target user' do
        expect(Puppet::Util).to receive(:uid).with(uid).twice.and_return 9000
        expect(Puppet::Util::SUIDManager).to receive(:uid).and_return 9000
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-l'], options).and_return(Puppet::Util::Execution::ProcessOutput.new(crontab, 0))
        expect(cron.read).to eq(crontab)
      end

      it 'treats an absent crontab as empty' do
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-l'], user_options).and_raise(Puppet::ExecutionFailure, absent_crontab)
        expect(cron.read).to eq('')
      end

      it "treats a nonexistent user's crontab as empty" do
        expect(Puppet::Util).to receive(:uid).with(uid).and_return nil

        expect(cron.read).to eq('')
      end

      it 'returns empty if the user is not authorized to use cron' do
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-l'], user_options).and_raise(Puppet::ExecutionFailure, unauthorized_crontab)
        expect(cron.read).to eq('')
      end
    end

    describe '#remove' do
      it 'runs crontab -r as the target user' do
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-r'], user_options)
        cron.remove
      end

      it 'does not switch user if current user is the target user' do
        expect(Puppet::Util).to receive(:uid).with(uid).and_return 9000
        expect(Puppet::Util::SUIDManager).to receive(:uid).and_return 9000
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', '-r'], options)
        cron.remove
      end
    end

    describe '#write' do
      let!(:tmp_cron) { Tempfile.new('puppet_crontab_spec') }
      let!(:tmp_cron_path) { tmp_cron.path }

      before :each do
        allow(Puppet::Util).to receive(:uid).with(uid).and_return 9000
        allow(Tempfile).to receive(:new).with("puppet_#{name}", encoding: Encoding.default_external).and_return tmp_cron
      end

      after :each do
        allow(File).to receive(:chown).and_call_original
      end

      it 'runs crontab as the target user on a temporary file' do
        expect(File).to receive(:chown).with(9000, nil, tmp_cron_path)
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', tmp_cron_path], user_options)

        expect(tmp_cron).to receive(:print).with("foo\n")
        cron.write "foo\n"

        expect(Puppet::FileSystem).not_to exist(tmp_cron_path)
      end

      it 'does not switch user if current user is the target user' do
        expect(Puppet::Util::SUIDManager).to receive(:uid).and_return 9000
        expect(File).to receive(:chown).with(9000, nil, tmp_cron_path)
        expect(Puppet::Util::Execution).to receive(:execute).with(['crontab', tmp_cron_path], options)

        expect(tmp_cron).to receive(:print).with("foo\n")
        cron.write "foo\n"

        expect(Puppet::FileSystem).not_to exist(tmp_cron_path)
      end
    end
  end

  describe 'the suntab filetype', unless: Puppet::Util::Platform.windows? do
    let(:type)           { described_class.filetype(:suntab) }
    let(:name)           { type.name }
    let(:crontab_output) { 'suntab_output' }

    # possible crontab output was taken from here:
    # https://docs.oracle.com/cd/E19082-01/819-2380/sysrescron-60/index.html
    let(:absent_crontab) do
      'crontab: can\'t open your crontab file'
    end
    let(:unauthorized_crontab) do
      'crontab: you are not authorized to use cron. Sorry.'
    end

    it_behaves_like 'crontab provider'
  end

  describe 'the aixtab filetype', unless: Puppet::Util::Platform.windows? do
    let(:type)           { described_class.filetype(:aixtab) }
    let(:name)           { type.name }
    let(:crontab_output) { 'aixtab_output' }

    let(:absent_crontab) do
      '0481-103 Cannot open a file in the /var/spool/cron/crontabs directory.'
    end
    let(:unauthorized_crontab) do
      '0481-109 You are not authorized to use the cron command.'
    end

    it_behaves_like 'crontab provider'
  end
end