require_relative "../../../../base"

describe 'VagrantPlugins::GuestAlpine::Cap::ChangeHostname' do
    let(:described_class) do
        VagrantPlugins::GuestAlpine::Plugin.components.guest_capabilities[:alpine].get(:change_host_name)
    end
    let(:machine) { double('machine') }
    let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
    let(:old_hostname) { 'oldhostname.olddomain.tld' }

    before do
        allow(machine).to receive(:communicate).and_return(communicator)
        communicator.stub_command('hostname -f', stdout: old_hostname)
    end

    after do
        communicator.verify_expectations!
    end

    describe '.change_host_name' do
        it 'updates /etc/hostname on the machine' do
            communicator.expect_command("echo 'newhostname' > /etc/hostname")
            described_class.change_host_name(machine, 'newhostname.newdomain.tld')
        end

        it 'does nothing when the provided hostname is not different' do
            described_class.change_host_name(machine, 'oldhostname.olddomain.tld')
            expect(communicator.received_commands).to eq(['hostname -f'])
        end

        it 'refreshes the hostname service with the hostname command' do
            communicator.expect_command('hostname -F /etc/hostname')
            described_class.change_host_name(machine, 'newhostname.newdomain.tld')
        end

        it 'renews dhcp on the system with the new hostname' do
            communicator.expect_command('ifdown -a; ifup -a; ifup eth0')
            described_class.change_host_name(machine, 'newhostname.newdomain.tld')
        end

        describe 'flipping out the old hostname in /etc/hosts' do
            let(:sed_command) do
                # Here we run the change_host_name through and extract the recorded sed
                # command from the dummy communicator
                described_class.change_host_name(machine, 'newhostname.newdomain.tld')
                communicator.received_commands.find { |cmd| cmd =~ /^sed/ }
            end

            # Now we extract the regexp from that sed command so we can do some
            # verification on it
            let(:expression) { sed_command.sub(%r{^sed -ri '\(.*\)' /etc/hosts$}, "\1") }
            let(:search)     { Regexp.new(expression.split('@')[1], Regexp::EXTENDED) }
            let(:replace)    { expression.split('@')[2] }

            let(:grep_command) { "grep '#{old_hostname}' /etc/hosts" }

            before do
                communicator.stub_command(grep_command, exit_code: 0)
            end

            it 'works on an simple /etc/hosts file' do
                original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
                    127.0.0.1 localhost
                    127.0.1.1 oldhostname.olddomain.tld oldhostname
                ETC_HOSTS

                modified_etc_hosts = original_etc_hosts.gsub(search, replace)

                expect(modified_etc_hosts).to eq <<-RESULT.gsub(/^ */, '')
                    127.0.0.1 localhost
                    127.0.1.1 newhostname.newdomain.tld newhostname
                RESULT
            end

            it 'does not modify lines which contain similar hostnames' do
                original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
                    127.0.0.1 localhost
                    127.0.1.1 oldhostname.olddomain.tld oldhostname
                    # common prefix, but different fqdn
                    192.168.12.34 oldhostname.olddomain.tld.different
                    # different characters at the dot
                    192.168.34.56 oldhostname-olddomain.tld
                ETC_HOSTS

                modified_etc_hosts = original_etc_hosts.gsub(search, replace)

                expect(modified_etc_hosts).to eq <<-RESULT.gsub(/^ */, '')
                    127.0.0.1 localhost
                    127.0.1.1 newhostname.newdomain.tld newhostname
                    # common prefix, but different fqdn
                    192.168.12.34 oldhostname.olddomain.tld.different
                    # different characters at the dot
                    192.168.34.56 oldhostname-olddomain.tld
                RESULT
            end

            it "appends 127.0.1.1 if it isn't there" do
                communicator.stub_command(grep_command, exit_code: 1)
                described_class.change_host_name(machine, 'newhostname.newdomain.tld')

                sed = communicator.received_commands.find { |cmd| cmd =~ /^sed/ }
                expect(sed).to be_nil

                echo = communicator.received_commands.find { |cmd| cmd =~ /^echo/ }
                expect(echo).to_not be_nil
            end

            context 'when the old fqdn has a trailing dot' do
                let(:old_hostname) { 'oldhostname.withtrailing.dot.' }

                it 'modifies /etc/hosts properly' do
                    original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
                        127.0.0.1 localhost
                        127.0.1.1 oldhostname.withtrailing.dot. oldhostname
                    ETC_HOSTS

                    modified_etc_hosts = original_etc_hosts.gsub(search, replace)

                    expect(modified_etc_hosts).to eq <<-RESULT.gsub(/^ */, '')
                        127.0.0.1 localhost
                        127.0.1.1 newhostname.newdomain.tld newhostname
                    RESULT
                end
            end
        end
    end
end
