require 'spec_helper'

describe Geo::FileUploadService do
  include EE::GeoHelpers

  set(:node) { create(:geo_node, :primary) }

  let(:transfer_request) { Gitlab::Geo::TransferRequest.new(request_data) }
  let(:req_header) { transfer_request.headers['Authorization'] }

  before do
    stub_current_geo_node(node)
  end

  shared_examples 'no authorization header' do
    it 'returns nil' do
      service = described_class.new(params, nil)

      expect(service.execute).to be_nil
    end
  end

  shared_examples 'wrong scope' do
    context 'at least one scope parameter is wrong' do
      let(:transfer_request) { Gitlab::Geo::TransferRequest.new(request_data.merge(file_type: 'wrong')) }

      it 'returns nil' do
        service = described_class.new(params, req_header)

        expect(service.execute).to be_nil
      end
    end
  end

  describe '#execute' do
    context 'user avatar' do
      let(:user) { create(:user, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png')) }
      let(:upload) { Upload.find_by(model: user, uploader: 'AvatarUploader') }
      let(:params) { { id: upload.id, type: 'avatar' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:avatar, upload).request_data }

      it 'sends avatar file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(user.avatar.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'group avatar' do
      let(:group) { create(:group, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png')) }
      let(:upload) { Upload.find_by(model: group, uploader: 'AvatarUploader') }
      let(:params) { { id: upload.id, type: 'avatar' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:avatar, upload).request_data }

      it 'sends avatar file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(group.avatar.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'project avatar' do
      let(:project) { create(:project, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png')) }
      let(:upload) { Upload.find_by(model: project, uploader: 'AvatarUploader') }
      let(:params) { { id: upload.id, type: 'avatar' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:avatar, upload).request_data }

      it 'sends avatar file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(project.avatar.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'attachment' do
      let(:note) { create(:note, :with_attachment) }
      let(:upload) { Upload.find_by(model: note, uploader: 'AttachmentUploader') }
      let(:params) { { id: upload.id, type: 'attachment' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:attachment, upload).request_data }

      it 'sends attachment file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(note.attachment.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'file upload' do
      let(:project) { create(:project) }
      let(:upload) { Upload.find_by(model: project, uploader: 'FileUploader') }
      let(:params) { { id: upload.id, type: 'file' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:file, upload).request_data }
      let(:file) { fixture_file_upload('spec/fixtures/dk.png', 'image/png') }

      before do
        FileUploader.new(project).store!(file)
      end

      it 'sends the file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to end_with('dk.png')
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'namespace file upload' do
      let(:group) { create(:group) }
      let(:upload) { Upload.find_by(model: group, uploader: 'NamespaceFileUploader') }
      let(:params) { { id: upload.id, type: 'file' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:file, upload).request_data }
      let(:file) { fixture_file_upload('spec/fixtures/dk.png', 'image/png') }

      before do
        NamespaceFileUploader.new(group).store!(file)
      end

      it 'sends the file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to end_with('dk.png')
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'LFS Object' do
      let(:lfs_object) { create(:lfs_object, :with_file) }
      let(:params) { { id: lfs_object.id, type: 'lfs' } }
      let(:request_data) { Gitlab::Geo::LfsTransfer.new(lfs_object).request_data }

      it 'sends LFS file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(lfs_object.file.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'job artifact' do
      let(:job_artifact) { create(:ci_job_artifact, :with_file) }
      let(:params) { { id: job_artifact.id, type: 'job_artifact' } }
      let(:request_data) { Gitlab::Geo::JobArtifactTransfer.new(job_artifact).request_data }

      it 'sends job artifact file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to eq(job_artifact.file.path)
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end

    context 'import export archive' do
      let(:project) { create(:project) }
      let(:upload) { Upload.find_by(model: project, uploader: 'ImportExportUploader') }
      let(:params) { { id: upload.id, type: 'import_export' } }
      let(:request_data) { Gitlab::Geo::FileTransfer.new(:import_export, upload).request_data }
      let(:file) { fixture_file_upload('spec/fixtures/project_export.tar.gz') }

      before do
        ImportExportUploader.new(project).store!(file)
      end

      it 'sends the file' do
        service = described_class.new(params, req_header)

        response = service.execute

        expect(response[:code]).to eq(:ok)
        expect(response[:file].path).to end_with('tar.gz')
      end

      include_examples 'no authorization header'
      include_examples 'wrong scope'
    end
  end
end
