require 'spec_helper'

describe VulnerabilityFeedbackModule::CreateService, '#execute' do
  let(:group)   { create(:group) }
  let(:project) { create(:project, :public, namespace: group) }
  let(:user)    { create(:user) }
  let(:pipeline) { create(:ci_pipeline, project: project) }

  before do
    group.add_developer(user)
  end

  context 'when params are valid' do
    let(:feedback_params) do
      {
        feedback_type: 'dismissal', pipeline_id: pipeline.id, category: 'sast',
        project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8',
        vulnerability_data: {
          category: 'sast',
          priority: 'Low', line: '41',
          file: 'subdir/src/main/java/com/gitlab/security_products/tests/App.java',
          cve: '818bf5dacb291e15d9e6dc3c5ac32178:PREDICTABLE_RANDOM',
          name: 'Predictable pseudorandom number generator',
          description: 'Description of Predictable pseudorandom number generator',
          tool: 'find_sec_bugs'
        }
      }
    end

    context 'when feedback_type is dismissal' do
      let(:result) { described_class.new(project, user, feedback_params).execute }

      it 'creates the feedback with the given params' do
        expect(result[:status]).to eq(:success)
        feedback = result[:vulnerability_feedback]
        expect(feedback).to be_persisted
        expect(feedback.project).to eq(project)
        expect(feedback.author).to eq(user)
        expect(feedback.feedback_type).to eq('dismissal')
        expect(feedback.pipeline_id).to eq(pipeline.id)
        expect(feedback.category).to eq('sast')
        expect(feedback.project_fingerprint).to eq('418291a26024a1445b23fe64de9380cdcdfd1fa8')
        expect(feedback.dismissal?).to eq(true)
        expect(feedback.issue?).to eq(false)
        expect(feedback.issue).to be_nil
      end
    end

    context 'when feedback_type is issue' do
      let(:result) do
        described_class.new(
          project,
          user,
          feedback_params.merge(feedback_type: 'issue')
        ).execute
      end

      it 'creates the feedback with the given params' do
        expect(result[:status]).to eq(:success)
        feedback = result[:vulnerability_feedback]
        expect(feedback).to be_persisted
        expect(feedback.project).to eq(project)
        expect(feedback.author).to eq(user)
        expect(feedback.feedback_type).to eq('issue')
        expect(feedback.pipeline_id).to eq(pipeline.id)
        expect(feedback.category).to eq('sast')
        expect(feedback.project_fingerprint).to eq('418291a26024a1445b23fe64de9380cdcdfd1fa8')
        expect(feedback.dismissal?).to eq(false)
        expect(feedback.issue?).to eq(true)
        expect(feedback.issue).to be_an(Issue)
      end

      it 'delegates the Issue creation to CreateFromVulnerabilityDataService' do
        expect_any_instance_of(Issues::CreateFromVulnerabilityDataService)
          .to receive(:execute).once.and_call_original

        expect(result[:status]).to eq(:success)
      end
    end
  end

  context 'when params are invalid' do
    context 'when vulnerability_data params is missing and feedback_type is issue' do
      let(:feedback_params) do
        {
          feedback_type: 'issue', pipeline_id: pipeline.id, category: 'sast',
          project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8'
        }
      end

      let(:result) { described_class.new(project, user, feedback_params).execute }

      it 'returns error with correct message' do
        expect(result[:status]).to eq(:error)
        expect(result[:message][:vulnerability_data]).to eq(["can't be blank"])
      end
    end

    context 'when feedback_type is invalid' do
      let(:feedback_params) do
        {
          feedback_type: 'foo', pipeline_id: pipeline.id, category: 'sast',
          project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8'
        }
      end

      let(:result) { described_class.new(project, user, feedback_params).execute }

      it 'returns error with correct message' do
        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq("'foo' is not a valid feedback_type")
      end
    end
  end
end
