# frozen_string_literal: true

describe Gitlab::QA::Docker::Engine do
  let(:docker) { spy('docker') }

  subject(:docker_engine) { described_class.new }

  before do
    stub_const('Gitlab::QA::Support::ShellCommand', docker)
  end

  describe '#exec' do
    before do
      allow(docker_engine).to receive(:privileged_command?).and_return(false)
    end

    context 'with secrets to mask' do
      it 'passes secrets to Docker::Command' do
        expect(Gitlab::QA::Docker::Command).to receive(:execute).with(anything, mask_secrets: ['secret'])

        docker_engine.exec('test', 'command', mask_secrets: ['secret']) { nil }
      end
    end

    context 'without secrets to mask' do
      it 'does not pass any secrets to Docker::Command' do
        expect(Gitlab::QA::Docker::Command).to receive(:execute).with(anything, mask_secrets: nil)

        docker_engine.exec('test', 'command') { nil }
      end
    end
  end

  describe '#pull' do
    it 'pulls docker image' do
      docker_engine.pull(image: 'gitlab/gitlab-ce', tag: 'nightly')

      expect(docker).to have_received(:new)
        .with(eq('docker pull -q gitlab/gitlab-ce:nightly'), anything)
    end

    context 'when given an image name with no tag' do
      it 'pulls docker image' do
        docker_engine.pull(image: 'gitlab/gitlab-ce')

        expect(docker).to have_received(:new)
          .with(eq('docker pull -q gitlab/gitlab-ce'), anything)
      end
    end

    context 'when given an image name that includes a tag' do
      it 'pulls docker image' do
        docker_engine.pull(image: 'gitlab/gitlab-ce:nightly')

        expect(docker).to have_received(:new)
          .with(eq('docker pull -q gitlab/gitlab-ce:nightly'), anything)
      end
    end

    context 'when quiet pull is disabled' do
      it 'pulls without quiet option' do
        docker_engine.pull(image: 'gitlab/gitlab-ce:nightly', quiet: false)

        expect(docker).to have_received(:new)
          .with(eq('docker pull gitlab/gitlab-ce:nightly'), anything)
      end
    end
  end

  describe '#run' do
    it 'runs docker container' do
      docker_engine.run(image: 'gitlab/gitlab-ce', tag: 'nightly', args: ['cmd'])

      expect(docker).to have_received(:new)
        .with(eq('docker run gitlab/gitlab-ce:nightly cmd'), anything)
    end

    context 'when given an image name with no tag' do
      it 'runs docker container' do
        docker_engine.run(image: 'gitlab/gitlab-ce', args: ['cmd'])

        expect(docker).to have_received(:new)
          .with(eq('docker run gitlab/gitlab-ce cmd'), anything)
      end
    end

    context 'when given an image name that includes a tag' do
      it 'runs docker container' do
        docker_engine.run(image: 'gitlab/gitlab-ce:nightly', args: ['cmd'])

        expect(docker).to have_received(:new)
          .with(eq('docker run gitlab/gitlab-ce:nightly cmd'), anything)
      end
    end

    context 'with secrets to mask' do
      it 'passes secrets to Docker::Command' do
        docker_engine.run(image: 'gitlab/gitlab-ce', mask_secrets: ['secret'])

        expect(docker).to have_received(:new).with(anything, a_hash_including(mask_secrets: ['secret']))
      end
    end

    context 'without secrets to mask' do
      it 'does not pass any secrets to Docker::Command' do
        docker_engine.run(image: 'gitlab/gitlab-ce')

        expect(docker).to have_received(:new).with(anything, a_hash_including(mask_secrets: nil))
      end
    end
  end

  describe '#stop' do
    it 'stops docker container' do
      docker_engine.stop('some_container')

      expect(docker).to have_received(:new)
        .with(eq('docker stop some_container'), anything)
    end
  end

  describe '#port' do
    it 'returns exposed TCP port' do
      docker_engine.port('some_container', 80)

      expect(docker).to have_received(:new)
        .with(eq('docker port some_container 80/tcp'), anything)
    end
  end

  describe '#write_files' do
    it 'writes a file on the container' do
      docker_engine.write_files('test') do |f|
        f.write('/opt/test', 'content')
      end

      expect(docker).to have_received(:new)
        .with(eq("docker exec test bash -c \"echo \\\"content\\\" > /opt/test;\""), anything)
    end

    it 'writes a file on the container with a variable' do
      docker_engine.write_files('test') do |f|
        f.write('/opt/test', 'single quotes to stop $myvar from expanding', false)
      end

      expect(docker).to have_received(:new).with(
        eq("docker exec test bash -c \"echo 'single quotes to stop $myvar from expanding' > /opt/test;\""),
        anything
      )
    end

    it 'appends to a file on the container' do
      docker_engine.write_files('test') do |f|
        f.append('/opt/test', 'content')
      end

      expect(docker).to have_received(:new)
        .with(eq("docker exec test bash -c \"echo \\\"content\\\" >> /opt/test;\""), anything)
    end

    context 'with secrets to mask' do
      it 'passes secrets to exec' do
        expect(docker_engine).to receive(:exec).with('test', nil, mask_secrets: ['secret'])

        docker_engine.write_files('test', mask_secrets: ['secret']) { nil }
      end
    end

    context 'without secrets to mask' do
      it 'does not pass any secrets to exec' do
        expect(docker_engine).to receive(:exec).with('test', nil, mask_secrets: nil)

        docker_engine.write_files('test') { nil }
      end
    end
  end
end
