# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Security::VulnerabilityCountingService, '#execute' do
  before do
    stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, dast: true)
  end

  let_it_be(:pipeline) { create(:ci_pipeline, :success) }

  let_it_be(:build_ds) { create(:ci_build, :success, name: 'dependency_scanning', pipeline: pipeline) }
  let_it_be(:artifact_ds) { create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds) }
  let_it_be(:report_ds) { create(:ci_reports_security_report, type: :dependency_scanning) }

  let_it_be(:build_sast) { create(:ci_build, :success, name: 'sast', pipeline: pipeline) }
  let_it_be(:artifact_sast) { create(:ee_ci_job_artifact, :sast, job: build_sast) }
  let_it_be(:report_sast) { create(:ci_reports_security_report, type: :sast) }

  let_it_be(:build_dast) { create(:ci_build, :success, name: 'dast', pipeline: pipeline) }
  let_it_be(:artifact_dast) { create(:ee_ci_job_artifact, :dast, job: build_dast) }
  let_it_be(:report_dast) { create(:ci_reports_security_report, type: :dast) }

  let_it_be(:build_cs) { create(:ci_build, :success, name: 'container_scanning', pipeline: pipeline) }
  let_it_be(:artifact_cs) { create(:ee_ci_job_artifact, :container_scanning, job: build_cs) }
  let_it_be(:report_cs) { create(:ci_reports_security_report, type: :container_scanning) }

  context "The pipeline has security builds" do
    before(:all) do
      ds_content = File.read(artifact_ds.file.path)
      Gitlab::Ci::Parsers::Security::DependencyScanning.parse!(ds_content, report_ds)
      report_ds.merge!(report_ds)

      sast_content = File.read(artifact_sast.file.path)
      Gitlab::Ci::Parsers::Security::Sast.parse!(sast_content, report_sast)
      report_sast.merge!(report_sast)

      dast_content = File.read(artifact_dast.file.path)
      Gitlab::Ci::Parsers::Security::Dast.parse!(dast_content, report_dast)
      report_dast.merge!(report_dast)

      cs_content = File.read(artifact_cs.file.path)
      Gitlab::Ci::Parsers::Security::ContainerScanning.parse!(cs_content, report_cs)
      report_cs.merge!(report_cs)

      { artifact_cs => report_cs, artifact_dast => report_dast, artifact_ds => report_ds, artifact_sast => report_sast }.each do |artifact, report|
        scan = create(:security_scan, scan_type: artifact.job.name, build: artifact.job)

        report.findings.each_with_index do |finding, index|
          create(:security_finding,
                 severity: finding.severity,
                 confidence: finding.confidence,
                 project_fingerprint: finding.project_fingerprint,
                 deduplicated: true,
                 position: index,
                 scan: scan)
        end
      end
    end

    context 'All report types are requested' do
      subject do
        described_class.new(pipeline, %w[sast dast container_scanning dependency_scanning]).execute
      end

      it {
        is_expected.to match(a_hash_including("sast" => 5,
                                              "dast" => 20,
                                              "container_scanning" => 8,
                                              "dependency_scanning" => 4))
      }
    end

    context 'Only the report type dast is requested' do
      subject { described_class.new(pipeline, %w[dast]).execute }

      it {
        is_expected.to eq({ "dast" => 20 })
      }
    end
  end

  context "The Pipeline has no security builds" do
    let_it_be(:pipeline) { create(:ci_pipeline, :success) }

    subject { described_class.new(pipeline, %w[sast dast container_scanning dependency_scanning]).execute }

    it {
      is_expected.to match(a_hash_including("sast" => 0,
                                            "dast" => 0,
                                            "container_scanning" => 0,
                                            "dependency_scanning" => 0))
    }
  end

  context 'performance' do
    it 'performs only one query' do
      count = ActiveRecord::QueryRecorder.new { described_class.new(pipeline, %w[dast]).execute }.count
      expect(count).to eq(1)

      count = ActiveRecord::QueryRecorder.new { described_class.new(pipeline, %w[dast sast container_scanning]).execute }.count
      expect(count).to eq(1)
    end
  end
end
