require 'stringio' module Omnibus describe Packager::Base do let(:project) do double('project', name: 'hamlet', build_version: '1.0.0', iteration: '12902349', mac_pkg_identifier: 'com.chef.hamlet', install_path: '/opt/hamlet', package_scripts_path: 'package-scripts', files_path: 'files', package_dir: 'pkg', package_tmp: 'pkg-tmp', resources_path: nil, friendly_name: 'HAMLET', ) end subject { described_class.new(project) } it 'includes Util' do expect(subject).to be_a(Util) end it 'delegates #name to @project' do expect(subject.name).to eq(project.name) end it 'delegates #friendly_name to @project' do expect(subject.friendly_name).to eq(project.friendly_name) end it 'delegates #version to @project' do expect(subject.version).to eq(project.build_version) end it 'delegates #iteration to @project' do expect(subject.iteration).to eq(project.iteration) end it 'delegates #identifer to @project' do expect(subject.identifier).to eq(project.mac_pkg_identifier) end it 'delegates #scripts to @project' do expect(subject.scripts).to eq(project.package_scripts_path) end it 'delegates #files_path to @project' do expect(subject.files_path).to eq(project.files_path) end it 'delegates #package_dir to @project' do expect(subject.package_dir).to eq(project.package_dir) end describe '.setup' do it 'sets the value of the block' do block = proc {} described_class.setup(&block) expect(described_class.setup).to eq(block) end end describe '.validate' do it 'sets the value of the block' do block = proc {} described_class.validate(&block) expect(described_class.validate).to eq(block) end end describe '.build' do it 'sets the value of the block' do block = proc {} described_class.build(&block) expect(described_class.build).to eq(block) end it 'is a required phase' do described_class.instance_variable_set(:@build, nil) expect { described_class.build }.to raise_error(AbstractMethod) end end describe '.clean' do it 'sets the value of the block' do block = proc {} described_class.clean(&block) expect(described_class.clean).to eq(block) end end describe '#create_directory' do before { FileUtils.stub(:mkdir_p) } it 'creates the directory' do expect(FileUtils).to receive(:mkdir_p).with('/foo/bar') subject.create_directory('/foo/bar') end it 'returns the path' do expect(subject.create_directory('/foo/bar')).to eq('/foo/bar') end end describe '#remove_directory' do before { FileUtils.stub(:rm_rf) } it 'remove the directory' do expect(FileUtils).to receive(:rm_rf).with('/foo/bar') subject.remove_directory('/foo/bar') end end describe '#purge_directory' do before do subject.stub(:remove_directory) subject.stub(:create_directory) end it 'removes and creates the directory' do expect(subject).to receive(:remove_directory).with('/foo/bar') expect(subject).to receive(:create_directory).with('/foo/bar') subject.purge_directory('/foo/bar') end end describe '#copy_file' do before { FileUtils.stub(:cp) } it 'copies the file' do expect(FileUtils).to receive(:cp).with('foo', 'bar') subject.copy_file('foo', 'bar') end it 'returns the destination path' do expect(subject.copy_file('foo', 'bar')).to eq('bar') end end describe '#copy_directory' do before do FileUtils.stub(:cp_r) Dir.stub(:[]).and_return(['baz/file']) end it 'copies the directory' do expect(FileUtils).to receive(:cp_r).with(['baz/file'], 'bar') subject.copy_directory('baz', 'bar') end end describe '#render_template' do it 'return when source is not an erb template' do expect(File).not_to receive(:open) subject.render_template('source.txt') end shared_examples_for 'render_template' do let(:output) { StringIO.new } before do input = StringIO.new input.write('<%= friendly_name %>') input.rewind File.stub(:open).with(source_path).and_yield(input) File.stub(:open).with(expected_destination_path, 'w').and_yield(output) expect(subject).to receive(:remove_file).with(source_path) end it 'should render correctly' do subject.render_template(source_path, destination_path) expect(output.string).to eq('HAMLET') end end context 'when destination is specified' do let(:source_path) { 'source.txt.erb' } let(:destination_path) { 'destination.txt' } let(:expected_destination_path) { destination_path } include_examples 'render_template' end context 'when destination is not specified' do let(:source_path) { 'source.txt.erb' } let(:destination_path) { nil } let(:expected_destination_path) { 'source.txt' } include_examples 'render_template' end end describe '#remove_file' do before { FileUtils.stub(:rm_f) } it 'removes the file' do expect(FileUtils).to receive(:rm_f).with('/foo/bar') subject.remove_file('/foo/bar') end end describe '#execute' do before { subject.stub(:shellout!) } it 'shellsout' do expect(subject).to receive(:shellout!) .with('echo "hello"', timeout: 3600, cwd: anything) subject.execute('echo "hello"') end end describe '#assert_presence!' do it 'raises a MissingAsset exception when the file does not exist' do File.stub(:exist?).and_return(false) expect { subject.assert_presence!('foo') }.to raise_error(MissingAsset) end end describe '#run!' do before do described_class.stub(:validate).and_return(proc {}) described_class.stub(:setup).and_return(proc {}) described_class.stub(:build).and_return(proc {}) described_class.stub(:clean).and_return(proc {}) end it 'calls the methods in order' do expect(described_class).to receive(:setup).ordered expect(described_class).to receive(:validate).ordered expect(described_class).to receive(:build).ordered expect(described_class).to receive(:clean).ordered subject.run! end end describe '#staging_dir' do it 'is the project package tmp and underscored named' do name = "#{project.package_tmp}/base" expect(subject.send(:staging_dir)).to eq(File.expand_path(name)) end end describe '#staging_resources_path' do it 'is base/Resources under package temp' do name = "#{project.package_tmp}/base/Resources" expect(subject.send(:staging_resources_path)).to eq(File.expand_path(name)) end end describe '#resource' do it 'prefixes to the resources_path' do path = 'pkg-tmp/base/Resources/icon.png' expect(subject.send(:resource, 'icon.png')).to eq(File.expand_path(path)) end end describe '#resoures_path' do context 'when project does not define resources_path' do it 'is the files_path, underscored_name, and Resources' do path = "#{project.files_path}/base/Resources" expect(subject.send(:resources_path)).to eq(File.expand_path(path)) end end context 'when project defines resources_path' do before { project.stub(:resources_path).and_return('project/specific') } it 'is the project resources_path, underscored_name, and Resources' do path = 'project/specific/base/Resources' expect(subject.send(:resources_path)).to eq(File.expand_path(path)) end end end end end