require 'spec_helper'
require 'debci/runner/debci'
require 'debci/job'

describe Debci::Runner::Debci do
  def runner_for_job(**data)
    Debci::Runner::Debci.new(
      Debci::Job.new(**data)
    )
  end

  context 'calculating job parameters' do
    it 'escapes trigger' do
      runner = runner_for_job(trigger: 'foo bar')
      expect(runner.enqueue_parameters).to_not include('trigger:foo bar')
      expect(runner.enqueue_parameters).to include('trigger:foo+bar')
    end

    [
      'áéíóú',
      '`cat /etc/passwd`',
      '$(cat /etc/passwd)',
      "a\nb"
    ].each do |invalid|
      it('escapes \"%<invalid>s" in trigger' % { invalid: invalid }) do
        runner = runner_for_job(trigger: invalid)
        expect(runner.enqueue_parameters).to_not include(invalid)
      end
    end

    it 'handles multiple pinned packages' do
      runner = runner_for_job(pin_packages: [["src:foo", "src:bar", "unstable"]])
      expect(runner.enqueue_parameters).to include('pin-packages:unstable=src:foo,src:bar')
    end

    before do
      bullseye_security_signing_key =
        '-----BEGIN PGP PUBLIC KEY BLOCK-----
      mQINBEo1mTQBEAD29YIKM0hM2IsB+TzBOpQja6h5hJ1gVeP7IWhC8E11jwaaoP1K
      SXESKFMVPt0es0aCSDftm5TVTvLl08MG9fZBFT8pERfkWTEWWhY1MJ28sV8PRBHf
      hN0mv5aduvgVx32+aCD0mWhI/3XHObf6c/X9WMwEaH+6A9UFiXRCyflra9YOfHU
      inXj5aYllc2UNiNxPhJ5sQTv97hdVbb/dFa+t9A2LFgPADbwUW+ShJN8zGR3XMne
      lXTcOgPhBadiNPPi8PztfOgcUk/NqZ5H4i0cXXbZB6leWcGMMMiWNexapgea/Hvp
      aXT2kSIug7OySFXM4nhM4xGo426+r9QHx1dzndHP5AW+WRuJmi3hMEdj22ifIFrV
      XtwovTb6/R2nG7WLVSHKg1AuFvIfG1RrTaVUVMcXVGX83CB2qKjfMHFRyMKUxoK7
      cZZkgD+sst47L+P3MlrRPfuB6selEySIrcwXTxFiuhLf74Zc8AZZeOi5ae2GObGr
      b40wIT4HpJZO9M2YfZkMcnFsAqB8D4tPz9OjXiZdqNrXBMKJo0nsOFsYqkOCpnXP
      ic4HQvmEaEWzNuPlWFH54AQf3zAWMoawLXOfgAOYAc8gf1dxYOTMJEBIplBBj8ch
      ...
      -----END PGP PUBLIC KEY BLOCK-----'
      allow(Debci.extra_apt_sources_list).to receive(:find)
        .with('experimental')
        .and_return(Debci::ExtraAptSource.new('deb http://deb.debian.org/debian experimental main'))
      allow(Debci.extra_apt_sources_list).to receive(:find)
        .with('bullseye-security')
        .and_return(Debci::ExtraAptSource.new('deb http://security.debian.org/debian-security bullseye-security main', [], bullseye_security_signing_key))
    end

    it 'encodes each extra-apt-sources string to base64' do
      runner = runner_for_job(extra_apt_sources: ["experimental"])
      expect(runner.enqueue_parameters).to include(%r'extra-apt-source:([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?')
    end

    it 'handles multiple extra-apt-sources' do
      runner = runner_for_job(extra_apt_sources: ["experimental", "bullseye-security"])
      expect(runner.enqueue_parameters).to include("extra-apt-source:#{Base64.strict_encode64('deb http://deb.debian.org/debian experimental main')}")
      expect(runner.enqueue_parameters).to include("extra-apt-source:#{Base64.strict_encode64('deb http://security.debian.org/debian-security bullseye-security main')}")
    end

    it 'enqueues signing-key if present for an extra-apt-source' do
      runner = runner_for_job(extra_apt_sources: ["experimental", "bullseye-security"])
      expect(runner.enqueue_parameters.to_s.scan('signing-key').size).to eq(1)
    end

    it 'encodes signing-key of extra-apt-source to base64' do
      runner = runner_for_job(extra_apt_sources: ["bullseye-security"])
      expect(runner.enqueue_parameters).to include(%r'signing-key:([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?')
    end

    it 'handles autopkgtest' do
      implicit = runner_for_job
      expect(implicit.enqueue_parameters.grep(/autopkgtest:/)).to be_empty

      explicit = runner_for_job(autopkgtest: "git")
      expect(explicit.enqueue_parameters).to include('autopkgtest:git')
    end

    it 'handles the default backend' do
      runner = runner_for_job
      expect(runner.enqueue_parameters.grep(/backend:/).first).to match(/backend:\w/)
    end

    it 'handles a selected backend' do
      runner = runner_for_job(selected_backend: "somebackend")
      expect(runner.enqueue_parameters).to include("backend:somebackend")
    end
  end

  context 'actually sending to AMQP' do
    let(:package) { Debci::Package.create!(name: 'mypackage') }
    let(:theuser) { Debci::User.create!(username: 'user') }
    let(:job) do
      Debci::Job.create!(
        package: package,
        arch: "arm64",
        suite: "testing",
        requestor: theuser
      )
    end
    let(:runner) { Debci::Runner::Debci.new(job) }
    let(:queue) { double("Queue") }

    before do
      expect(Debci::AMQP).to receive(:get_queue).and_return(queue)
    end

    it 'sends AMQP message' do
      expect(runner).to receive(:enqueue_parameters).and_return(["foo:bar"])
      message = "#{job.package.name} #{job.suite} foo:bar"
      expect(queue).to receive(:publish).with(message, priority: nil)

      runner.submit
    end

    it 'uses job priority' do
      runner.job.priority = 7

      expect(queue).to receive(:publish).with(anything, priority: 7)

      runner.submit
    end
  end

  context 'selecting backend' do
    it 'delegates to Debci::Backend' do
      runner = runner_for_job(arch: 'arm64', requested_backend: 'incus-lxc')
      expect(Debci::Backend).to receive(:select).with('incus-lxc', 'arm64').and_return('foobar')
      expect(runner.select_backend).to eq('foobar')
    end
  end
end
