# frozen_string_literal: true

require 'rake_helper'

describe 'security tasks', :rake do
  before do
    allow(ReleaseTools::SharedStatus)
      .to receive(:critical_patch_release?)
      .and_return(false)
  end

  after do
    # rake tasks in the security namespace run the force_security task altering
    # the global state
    ENV.delete('SECURITY')
  end

  describe 'sync_git_tags', task: 'security:sync_git_tags' do
    it 'syncs git tags' do
      expect(ReleaseTools::Security::SyncGitRemotesService).to receive(:new)
        .with(['1.0', '2.0', 'v3.1'])
        .and_return(instance_double(ReleaseTools::Security::SyncGitRemotesService, execute: true))

      task.invoke('1.0 2.0 v3.1')
    end
  end

  describe 'prepare:review_security_fixes', task: 'security:prepare:review_security_fixes' do
    it 'verifies the fixes included in the patch release' do
      expect(ReleaseTools::Security::Prepare::FixesVerifier).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Prepare::FixesVerifier, execute: true))

      task.invoke
    end
  end

  describe 'prepare:appsec_issue', task: 'security:prepare:appsec_issue' do
    it 'creates the AppSec task issue' do
      expect(ReleaseTools::Security::Prepare::IssueCreator).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Prepare::IssueCreator, execute: true))

      task.invoke
    end
  end

  describe 'prepare:comms_issue', task: 'security:prepare:comms_issue' do
    it 'creates the AppSec task issue' do
      expect(ReleaseTools::Security::Prepare::IssueCreator).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Prepare::IssueCreator, execute: true))

      task.invoke
    end
  end

  describe 'publish:generate_dynamic_pipeline', task: 'security:publish:generate_dynamic_pipeline' do
    let(:versions) { ['1.0.1', '1.1.1', '1.2.3'] }
    let(:generated_jobs) { "dummy:output" }

    let(:publish_jobs) { instance_double(ReleaseTools::Security::Publish::DynamicPipeline) }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator) }

    before do
      allow(ReleaseTools::Security::Publish::DynamicPipeline).to receive(:new).with(versions).and_return(publish_jobs)

      allow(File).to receive(:write)

      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(coordinator).to receive(:versions).and_return(versions)
    end

    it 'correctly processes and writes a dynamic pipeline to a file' do
      expect(ReleaseTools::Security::Publish::DynamicPipeline).to receive(:new).with(versions).and_return(publish_jobs)
      expect(publish_jobs).to receive(:generate).and_return(generated_jobs)
      expect(File).to receive(:write).with('dynamic-gitlab-ci.yml', generated_jobs)
      task.invoke
    end
  end

  describe 'publish:move_blog_post', task: 'security:publish:move_blog_post' do
    it 'moves the blog post to the handbook canonical repo' do
      expect(ReleaseTools::Security::Publish::MoveBlogPost).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Publish::MoveBlogPost, execute: true))

      task.invoke
    end
  end

  describe 'publish:deploy_blog_post', task: 'security:publish:deploy_blog_post' do
    it 'publishes the patch release blog post' do
      expect(ReleaseTools::Security::Publish::DeployBlogPost).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Publish::DeployBlogPost, execute: true))

      task.invoke
    end
  end

  describe 'finalize:enable_security_target_processor', task: 'security:finalize:enable_security_target_processor' do
    it 'enables the security target processor' do
      expect(ReleaseTools::Security::Finalize::ToggleSecurityTargetProcessor).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::Finalize::ToggleSecurityTargetProcessor, execute: true))

      task.invoke
    end
  end

  describe 'process_security_target_issues', task: 'security:process_security_target_issues' do
    it 'runs the processor' do
      expect(ReleaseTools::Security::TargetIssuesProcessor).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::TargetIssuesProcessor, execute: true))

      task.invoke
    end
  end

  describe 'finalize:create_release_status_metric', task: 'security:finalize:create_release_status_metric' do
    it 'creates a new patch release status metric with open status' do
      expect(ReleaseTools::Metrics::PatchReleaseStatus).to receive(:new).with(status: :open)
        .and_return(instance_double(ReleaseTools::Metrics::PatchReleaseStatus, execute: true))

      task.invoke
    end
  end

  describe 'tag:generate_dynamic_pipeline', task: 'security:tag:generate_dynamic_pipeline' do
    let(:versions) { ['1.0.1', '1.1.1', '1.2.3'] }
    let(:generated_jobs) { "dummy:output" }

    let(:tag_jobs) { instance_double(ReleaseTools::Security::Tag::DynamicPipeline) }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator) }

    before do
      allow(ReleaseTools::Security::Tag::DynamicPipeline).to receive(:new).with(versions).and_return(tag_jobs)

      allow(File).to receive(:write)

      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(coordinator).to receive(:versions).and_return(versions)
    end

    it 'correctly processes and writes a dynamic pipeline to a file' do
      expect(ReleaseTools::Security::Tag::DynamicPipeline).to receive(:new).with(versions).and_return(tag_jobs)
      expect(tag_jobs).to receive(:generate).and_return(generated_jobs)
      expect(File).to receive(:write).with('dynamic-tag-gitlab-ci.yml', generated_jobs)
      task.invoke
    end
  end

  describe 'tag:check_omnibus_packages_tagging', task: 'security:tag:check_omnibus_packages_tagging' do
    let(:versions) { ['13.0.1', '13.1.1', '13.2.1'] }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator, versions: versions) }
    let(:tagging_service) { instance_double(ReleaseTools::Services::OmnibusPackages::Tagging) }

    before do
      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(ReleaseTools::Services::OmnibusPackages::Tagging).to receive(:new).and_return(tagging_service)
      allow(tagging_service).to receive(:execute).and_return(true)
    end

    it 'executes ReleaseTools::Services::OmnibusPackages::Tagging 3 times' do
      expect(tagging_service).to receive(:execute).exactly(3).times
      task.invoke
    end
  end

  describe 'verify:check_omnibus_packages_publishing', task: 'security:verify:check_omnibus_packages_publishing' do
    let(:versions) { ['13.0.1', '13.1.1', '13.2.1'] }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator, versions: versions) }
    let(:publishing_service) { instance_double(ReleaseTools::Services::OmnibusPackages::Publishing) }

    before do
      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(ReleaseTools::Services::OmnibusPackages::Publishing).to receive(:new).and_return(publishing_service)
      allow(publishing_service).to receive(:execute).and_return(true)
    end

    it 'executes ReleaseTools::Services::OmnibusPackages::Publishing 3 times' do
      expect(publishing_service).to receive(:execute).exactly(3).times

      task.invoke
    end
  end

  describe 'verify:check_docker_tags', task: 'security:verify:check_docker_tags' do
    let(:versions) { ['13.0.1', '13.1.1', '13.2.1'] }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator, versions: versions) }
    let(:verifier) { instance_double(ReleaseTools::DockerHub::Verifier) }

    before do
      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(ReleaseTools::DockerHub::Verifier).to receive(:new).and_return(verifier)
      allow(verifier).to receive(:execute).and_return(true)
    end

    it 'executes ReleaseTools::DockerHub::Verifier 3 times' do
      expect(verifier).to receive(:execute).exactly(3).times

      task.invoke
    end
  end

  describe 'disable_security_target_processor:verify_managed_version_projects', task: 'security:disable_security_target_processor:verify_managed_version_projects' do
    it 'runs the notification service' do
      expect(ReleaseTools::Security::ManagedVersioningNotificationService).to receive(:new)
        .and_return(instance_double(ReleaseTools::Security::ManagedVersioningNotificationService, execute: true))

      task.invoke
    end
  end

  describe 'update_paths:generate_dynamic_pipeline', task: 'security:update_paths:generate_dynamic_pipeline' do
    let(:versions) { ['1.2.1', '1.1.1', '1.0.3'] }
    let(:latest_version) { '1.2.1' }

    let(:dynamic_pipeline) { instance_double(ReleaseTools::UpdatePaths::DynamicPipeline) }
    let(:coordinator) { instance_double(ReleaseTools::PatchRelease::Coordinator) }

    before do
      allow(ReleaseTools::UpdatePaths::DynamicPipeline).to receive(:new).with(latest_version).and_return(dynamic_pipeline)
      allow(dynamic_pipeline).to receive(:generate)

      allow(File).to receive(:write)

      allow(ReleaseTools::PatchRelease::Coordinator).to receive(:new).and_return(coordinator)
      allow(coordinator).to receive(:versions).and_return(versions)
    end

    it 'calls generate method on the ReleaseTools::UpdatePaths::DynamicPipeline instance' do
      expect(ReleaseTools::UpdatePaths::DynamicPipeline).to receive(:new).with(latest_version).and_return(dynamic_pipeline)
      expect(dynamic_pipeline).to receive(:generate)
      task.invoke
    end

    it 'writes the generated YAML content to dynamic-gitlab-ci.yml' do
      expect(File).to receive(:write).with('dynamic-gitlab-ci.yml', dynamic_pipeline.generate)
      task.invoke
    end
  end
end
