# frozen_string_literal: true

# spec/lib/gitlab/qa/component/runner_ops_spec.rb

require 'spec_helper'
require 'securerandom'
require 'gitlab/qa/component/gitlab'

module Gitlab
  module QA
    describe Component::RunnerOps do
      let(:runner_ops) { described_class.new }
      let(:docker) { instance_double(Gitlab::QA::Docker::Engine) }
      let(:gitlab) do
        instance_double(
          Gitlab::QA::Component::Gitlab,
          address: "http://gitlab.example.com",
          class: Struct.new(:name).new("Gitlab::QA::Component::Gitlab")
        ).tap do |gitlab|
          allow(gitlab).to receive_messages(docker: docker, name: 'gitlab-instance', network: 'test-network', address: 'http://gitlab.example.com')
        end
      end

      let(:token) { 'abc123def456' }

      before do
        allow(SecureRandom).to receive(:hex).and_return(token)
      end

      describe '#setup_runner' do
        it 'sets up a runner by generating token and performing required operations' do
          expect(runner_ops).to receive(:add_runner_to_gitlab).with(gitlab, token)
          expect(runner_ops).to receive(:register_docker_runner).with(gitlab, token)

          runner_ops.setup_runner(gitlab)
        end
      end

      describe '#add_runner_to_gitlab' do
        it 'executes runner creation command in gitlab container' do
          expected_command = runner_ops.send(:create_runner_command, token)

          expect(gitlab.docker).to receive(:exec).with(
            gitlab.name,
            expected_command,
            mask_secrets: token
          )

          runner_ops.send(:add_runner_to_gitlab, gitlab, token)
        end
      end

      describe '#create_runner_command' do
        it 'generates correct runner creation command' do
          command = runner_ops.send(:create_runner_command, token)

          expect(command).to include(described_class::RUNNER_DESCRIPTION)
          expect(command).to include(token)
          expect(command).to include('runner_type: :instance_type')
        end
      end

      describe '#register_docker_runner' do
        let(:runner_name) { 'test-runner-1234' }

        before do
          allow(runner_ops).to receive(:generate_runner_name).and_return(runner_name)
          allow(runner_ops).to receive(:shell)
        end

        it 'executes docker command with correct parameters' do
          expected_command = runner_ops.send(:build_docker_command,
            runner_name: runner_name,
            network: gitlab.network,
            address: gitlab.address,
            token: token
          )

          expect(runner_ops).to receive(:shell).with(expected_command, mask_secrets: [token])
          runner_ops.send(:register_docker_runner, gitlab, token)
        end
      end

      describe '#build_docker_command' do
        let(:runner_name) { 'test-runner-1234' }

        it 'builds correct docker command' do
          command = runner_ops.send(:build_docker_command,
            runner_name: runner_name,
            network: gitlab.network,
            address: gitlab.address,
            token: token
          )

          expect(command).to include(described_class::DOCKER_IMAGE)
          expect(command).to include(runner_name)
          expect(command).to include(gitlab.network)
        end
      end

      describe '#build_registration_args' do
        let(:runner_name) { 'test-runner-1234' }

        it 'builds registration arguments with correct parameters' do
          args = runner_ops.send(:build_registration_args,
            name: runner_name,
            address: gitlab.address,
            token: token,
            network: gitlab.network
          )

          expect(args).to include("--name #{runner_name}")
          expect(args).to include("--url #{gitlab.address}")
          expect(args).to include("--token #{token}")
          expect(args).to include("--docker-image #{described_class::BUILD_IMAGE}")
          expect(args).to include("--docker-network-mode=#{gitlab.network}")
        end
      end

      describe '#runner_config' do
        it 'generates valid runner configuration' do
          config = runner_ops.send(:runner_config)

          expect(config).to include('concurrent = 1')
          expect(config).to include('check_interval = 0')
          expect(config).to include('session_timeout = 1800')
        end
      end

      describe '#register_command' do
        let(:runner_name) { 'test-runner-1234' }

        it 'generates valid registration command' do
          command = runner_ops.send(:register_command,
            runner_name,
            gitlab.address,
            token,
            gitlab.network
          )

          expect(command).to include('gitlab-runner register')
          expect(command).to include('gitlab-runner run')
          expect(command).to include("printf 'concurrent = 1\\ncheck_interval = 0\\n\\n[session_server]\\n  session_timeout = 1800' > /etc/gitlab-runner/config.toml")
        end
      end
    end
  end
end
