# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_shared_state, feature_category: :importers do
  let_it_be(:user_namespace) { create(:namespace) }
  let_it_be_with_reload(:project) do
    create(
      :project,
      :in_group,
      import_type: 'github',
      import_url: 'https://github.com/user/repo.git'
    )
  end

  let(:client) { instance_double(Gitlab::GithubImport::Client) }
  let(:settings) { Gitlab::GithubImport::Settings.new }
  let(:user_mapping_enabled) { true }
  let(:user_mapping_to_personal_namespace_owner_enabled) { true }

  subject(:finder) { described_class.new(project, client) }

  before do
    project.build_or_assign_import_data(data: {
      user_contribution_mapping_enabled: user_mapping_enabled,
      user_mapping_to_personal_namespace_owner_enabled: user_mapping_to_personal_namespace_owner_enabled
    })
  end

  describe '#author_id_for' do
    context 'with default author_key' do
      it 'returns the user ID for the author of an object' do
        user = { id: 4, login: 'kittens' }
        note = { author: user }

        expect(finder).to receive(:user_id_for).with(user, ghost: true).and_return(42)

        expect(finder.author_id_for(note)).to eq([42, true])
      end

      it 'returns the ID of the ghost id if no user ID could be found' do
        user = { id: 4, login: 'kittens' }
        note = { author: user }

        expect(finder).to receive(:user_id_for).with(user, ghost: true).and_return(Users::Internal.ghost.id)

        expect(finder.author_id_for(note)).to eq([Users::Internal.ghost.id, true])
      end

      it 'returns the ID of the ghost user when the object has no user' do
        note = { author: nil }

        expect(finder.author_id_for(note)).to eq([Users::Internal.ghost.id, true])
      end

      it 'returns the ID of the ghost user when the given object is nil' do
        expect(finder.author_id_for(nil)).to eq([Users::Internal.ghost.id, true])
      end
    end

    context 'with a non-default author_key' do
      let(:user) { { id: 4, login: 'kittens' } }

      shared_examples 'user ID finder' do |author_key|
        it 'returns the user ID for an object' do
          expect(finder).to receive(:user_id_for).with(user, ghost: true).and_return(42)

          expect(finder.author_id_for(issue_event, author_key: author_key)).to eq([42, true])
        end
      end

      context 'when the author_key parameter is :actor' do
        let(:issue_event) { { actor: user } }

        it_behaves_like 'user ID finder', :actor
      end

      context 'when the author_key parameter is :review_requester' do
        let(:issue_event) { { review_requester: user } }

        it_behaves_like 'user ID finder', :review_requester
      end
    end
  end

  describe '#user_id_for' do
    context 'when passed `nil`' do
      it 'returns the ghost user id' do
        expect(finder.user_id_for(nil)).to eq(Users::Internal.ghost.id)
      end

      context 'when `ghost:` is false' do
        it 'returns nil' do
          expect(finder.user_id_for(nil, ghost: false)).to be_nil
        end
      end
    end

    context 'when user is GitHub ghost user' do
      it 'returns the ghost user id' do
        expect(finder.user_id_for({ login: 'ghost' })).to eq(Users::Internal.ghost.id)
      end

      context 'when `ghost:` is false' do
        it 'returns nil' do
          expect(finder.user_id_for({ login: 'ghost' }, ghost: false)).to be_nil
        end
      end
    end

    context 'when user mapping is disabled' do
      let(:user_mapping_enabled) { false }

      it 'returns the user ID for the given user' do
        user = { id: 4, login: 'kittens' }

        expect(finder).to receive(:find).with(user[:id], user[:login]).and_return(42)
        expect(finder.user_id_for(user)).to eq(42)
      end
    end

    context 'when user mapping is enabled' do
      let!(:source_user) do
        create(:import_source_user,
          namespace_id: project.root_ancestor.id,
          source_user_identifier: '7',
          source_hostname: 'https://github.com'
        )
      end

      it 'returns the mapped_user_id of source user with matching user identifier' do
        user = { id: 7, login: 'anything' }

        expect(finder.user_id_for(user)).to eq(source_user.mapped_user_id)
      end

      it 'creates a new source user when user identifier does not match' do
        user = { id: 6, login: 'anything' }

        allow(client).to receive(:user).and_return({ name: 'Source name' })

        expect { finder.user_id_for(user) }.to change { Import::SourceUser.count }.by(1)
        expect(finder.user_id_for(user)).not_to eq(source_user.mapped_user_id)
      end

      context 'when the project is imported into a personal namespace' do
        before do
          project.update!(namespace: user_namespace)
        end

        it 'returns the user namespace owner id' do
          user = { id: 6, login: 'anything' }

          allow(client).to receive(:user).and_return({ name: 'Source name' })

          expect { finder.user_id_for(user) }.not_to change { Import::SourceUser.count }
          expect(finder.user_id_for(user)).to eq(user_namespace.owner_id)
        end

        context 'when user_mapping_to_personal_namespace_owner is disabled' do
          let(:user_mapping_to_personal_namespace_owner_enabled) { false }

          it 'returns the mapped_user_id of source user' do
            user = { id: 6, login: 'anything' }

            allow(client).to receive(:user).and_return({ name: 'Source name' })

            expect { finder.user_id_for(user) }.to change { Import::SourceUser.count }.by(1)
            expect(finder.user_id_for(user)).not_to eq(user_namespace.owner_id)
          end
        end
      end
    end
  end

  describe '#source_user' do
    context 'when source user exists' do
      let!(:source_user) do
        create(:import_source_user,
          namespace_id: project.root_ancestor.id,
          source_user_identifier: '7',
          source_hostname: 'https://github.com'
        )
      end

      it 'returns the existing source user' do
        user = { id: 7, login: 'kittens' }

        expect(finder.source_user(user)).to eq(source_user)
      end
    end

    context 'when source user does not exist' do
      it 'fetches the user source name from GitHub and creates a new source user' do
        user = { id: 7, login: 'kittens' }

        expect(client).to receive(:user).with('kittens').and_return({ name: 'Source name' })
        expect { finder.source_user(user) }.to change { Import::SourceUser.count }.by(1)
        expect(Import::SourceUser.last).to have_attributes(
          source_name: 'Source name',
          source_username: 'kittens',
          source_user_identifier: '7'
        )
      end

      context 'when GitHub user does not exist' do
        before do
          allow(client).to receive(:user).with('Copilot').and_raise(Octokit::NotFound)
        end

        it 'creates a new source user, logs, and sets the `source_name` to be the username' do
          user = { id: 7, login: 'Copilot' }

          expect(Gitlab::GithubImport::Logger).to receive(:info).with(hash_including(
            message: include('GitHub user not found.'),
            username: 'Copilot'
          ))
          expect { finder.source_user(user) }.to change { Import::SourceUser.count }.by(1)
          expect(Import::SourceUser.last).to have_attributes(
            source_name: 'Copilot',
            source_username: 'Copilot',
            source_user_identifier: '7'
          )
        end
      end
    end
  end

  describe '#find' do
    let(:user) { create(:user) }

    before do
      allow(finder).to receive(:email_for_github_username)
        .and_return(user.email)
    end

    context 'without a cache' do
      before do
        allow(finder).to receive(:find_from_cache).and_return([false, nil])
        expect(finder).to receive(:find_id_from_database).and_call_original
      end

      it 'finds a GitLab user for a GitHub user ID' do
        user.identities.create!(provider: :github, extern_uid: 42)

        expect(finder.find(42, user.username)).to eq(user.id)
      end

      it 'finds a GitLab user for a GitHub Email address' do
        expect(finder.find(42, user.username)).to eq(user.id)
      end
    end

    context 'with a cache' do
      it 'returns the cached user ID' do
        expect(finder).to receive(:find_from_cache).and_return([true, user.id])
        expect(finder).not_to receive(:find_id_from_database)

        expect(finder.find(42, user.username)).to eq(user.id)
      end

      it 'does not query the database if the cache key exists but is empty' do
        expect(finder).to receive(:find_from_cache).and_return([true, nil])
        expect(finder).not_to receive(:find_id_from_database)

        expect(finder.find(42, user.username)).to be_nil
      end
    end
  end

  describe '#find_from_cache' do
    it 'retrieves a GitLab user ID for a GitHub user ID' do
      expect(finder)
        .to receive(:cached_id_for_github_id)
        .with(42)
        .and_return([true, 4])

      expect(finder.find_from_cache(42)).to eq([true, 4])
    end

    it 'retrieves a GitLab user ID for a GitHub Email address' do
      email = 'kittens@example.com'

      expect(finder)
        .to receive(:cached_id_for_github_id)
        .with(42)
        .and_return([false, nil])

      expect(finder)
        .to receive(:cached_id_for_github_email)
        .with(email)
        .and_return([true, 4])

      expect(finder.find_from_cache(42, email)).to eq([true, 4])
    end

    it 'does not query the cache for an Email address when none is given' do
      expect(finder)
        .to receive(:cached_id_for_github_id)
        .with(42)
        .and_return([false, nil])

      expect(finder).not_to receive(:cached_id_for_github_id)

      expect(finder.find_from_cache(42)).to eq([false])
    end
  end

  describe '#find_id_from_database' do
    let(:user) { create(:user) }

    it 'returns the GitLab user ID for a GitHub user ID' do
      user.identities.create!(provider: :github, extern_uid: 42)

      expect(finder.find_id_from_database(42, user.email)).to eq(user.id)
    end

    it 'returns the GitLab user ID for a GitHub Email address' do
      expect(finder.find_id_from_database(42, user.email)).to eq(user.id)
    end
  end

  describe '#email_for_github_username' do
    let(:email) { 'kittens@example.com' }
    let(:username) { 'kittens' }
    let(:user) { {} }
    let(:etag) { 'etag' }
    let(:lease_name) { "gitlab:github_import:user_finder:#{username}" }
    let(:cache_key) { described_class::EMAIL_FOR_USERNAME_CACHE_KEY % username }
    let(:etag_cache_key) { described_class::USERNAME_ETAG_CACHE_KEY % username }
    let(:email_fetched_for_project_key) do
      format(described_class::EMAIL_FETCHED_FOR_PROJECT_CACHE_KEY, project: project.id, username: username)
    end

    subject(:email_for_github_username) { finder.email_for_github_username(username) }

    shared_examples 'returns and caches the email' do
      it 'returns the email' do
        expect(email_for_github_username).to eq(email)
      end

      it 'caches the email and expires the etag and project check caches' do
        expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, email).once
        expect(Gitlab::Cache::Import::Caching).to receive(:expire).with(etag_cache_key, 0).once
        expect(Gitlab::Cache::Import::Caching).to receive(:expire).with(email_fetched_for_project_key, 0).once

        email_for_github_username
        email_for_github_username
      end
    end

    shared_examples 'returns nil and caches a negative lookup' do
      it 'returns nil' do
        expect(email_for_github_username).to be_nil
      end

      it 'caches a blank email and marks the project as checked' do
        expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
        expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once

        email_for_github_username
        email_for_github_username
      end
    end

    shared_examples 'does not change caches' do
      it 'does not write to any of the caches' do
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(cache_key, anything)
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(email_fetched_for_project_key, anything)

        email_for_github_username
        email_for_github_username
      end
    end

    shared_examples 'a user resource not found on GitHub' do
      before do
        allow(client).to receive(:user).and_raise(::Octokit::NotFound)
      end

      it 'returns nil' do
        expect(email_for_github_username).to be_nil
      end

      it 'caches a blank email' do
        expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
        expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(email_fetched_for_project_key, anything)

        email_for_github_username
        email_for_github_username
      end
    end

    context 'when the email is cached' do
      before do
        Gitlab::Cache::Import::Caching.write(cache_key, email)
      end

      it 'returns the email from the cache' do
        expect(email_for_github_username).to eq(email)
      end

      it 'does not make a rate-limited API call' do
        expect(client).not_to receive(:user).with(username, { headers: {} })

        email_for_github_username
        email_for_github_username
      end
    end

    context 'when the email cache is nil' do
      context 'if the email has not been checked for the project' do
        context 'if the cached etag is nil' do
          before do
            allow(client).to receive_message_chain(:octokit, :last_response, :headers).and_return({ etag: etag })
          end

          it 'makes an API call' do
            expect(client).to receive(:user).with(username, { headers: {} }).and_return({ email: email }).once
            expect(finder).to receive(:in_lock).with(
              lease_name, sleep_sec: 0.2.seconds, retries: 30
            ).and_call_original

            email_for_github_username
          end

          context 'if the response contains an email' do
            before do
              allow(client).to receive(:user).and_return({ email: email })
            end

            it_behaves_like 'returns and caches the email'

            context 'when retried' do
              before do
                allow(finder).to receive(:in_lock).and_yield(true)
              end

              it_behaves_like 'returns and caches the email'
            end
          end

          context 'if the response does not contain an email' do
            before do
              allow(client).to receive(:user).and_return({})
            end

            it 'returns nil' do
              expect(email_for_github_username).to be_nil
            end

            it 'caches a blank email and etag and marks the project as checked' do
              expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
              expect(Gitlab::Cache::Import::Caching).to receive(:write).with(etag_cache_key, etag).once
              expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once

              email_for_github_username
              email_for_github_username
            end
          end
        end

        context 'if the cached etag is not nil' do
          before do
            Gitlab::Cache::Import::Caching.write(etag_cache_key, etag)
          end

          it 'makes a non-rate-limited API call' do
            expect(client).to receive(:user).with(username, { headers: { 'If-None-Match' => etag } }).once
            expect(finder).to receive(:in_lock).with(
              lease_name, sleep_sec: 0.2.seconds, retries: 30
            ).and_call_original

            email_for_github_username
          end

          context 'if the response contains an email' do
            before do
              allow(client).to receive(:user).and_return({ email: email })
            end

            it_behaves_like 'returns and caches the email'
          end

          context 'if the response does not contain an email' do
            before do
              allow(client).to receive(:user).and_return({})
            end

            it_behaves_like 'returns nil and caches a negative lookup'
          end

          context 'if the response is nil' do
            before do
              allow(client).to receive(:user).and_return(nil)
            end

            it 'returns nil' do
              expect(email_for_github_username).to be_nil
            end

            it 'marks the project as checked' do
              expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(cache_key, anything)
              expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
              expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once

              email_for_github_username
              email_for_github_username
            end
          end
        end
      end

      context 'if the email has been checked for the project' do
        before do
          Gitlab::Cache::Import::Caching.write(email_fetched_for_project_key, 1)
        end

        it 'returns nil' do
          expect(email_for_github_username).to be_nil
        end

        it_behaves_like 'does not change caches'
      end

      it_behaves_like 'a user resource not found on GitHub'
    end

    context 'when the email cache is blank' do
      before do
        Gitlab::Cache::Import::Caching.write(cache_key, '')
      end

      context 'if the email has not been checked for the project' do
        context 'if the cached etag is not nil' do
          before do
            Gitlab::Cache::Import::Caching.write(etag_cache_key, etag)
          end

          it 'makes a non-rate-limited API call' do
            expect(client).to receive(:user).with(username, { headers: { 'If-None-Match' => etag } }).once
            expect(finder).to receive(:in_lock).with(
              lease_name, sleep_sec: 0.2.seconds, retries: 30
            ).and_call_original

            email_for_github_username
          end

          context 'if the response contains an email' do
            before do
              allow(client).to receive(:user).and_return({ email: email })
            end

            it_behaves_like 'returns and caches the email'
          end

          context 'if the response does not contain an email' do
            before do
              allow(client).to receive(:user).and_return({})
            end

            it_behaves_like 'returns nil and caches a negative lookup'
          end

          context 'if the response is nil' do
            before do
              allow(client).to receive(:user).and_return(nil)
            end

            it_behaves_like 'returns nil and caches a negative lookup'
          end

          it_behaves_like 'a user resource not found on GitHub'
        end

        context 'if the cached etag is nil' do
          context 'when lock was executed by another process and an email was fetched' do
            it 'does not fetch user detail' do
              expect(finder).to receive(:read_email_from_cache).ordered.and_return('')
              expect(finder).to receive(:read_email_from_cache).ordered.and_return(email)
              expect(finder).to receive(:in_lock).and_yield(true)
              expect(client).not_to receive(:user)

              email_for_github_username
            end
          end

          context 'when lock was executed by another process and an email in cache is still blank' do
            it 'fetch user detail' do
              expect(finder).to receive(:read_email_from_cache).ordered.and_return('')
              expect(finder).to receive(:read_email_from_cache).ordered.and_return('')
              expect(finder).to receive(:read_etag_from_cache).and_return(etag)
              expect(finder).to receive(:in_lock).and_yield(true)
              expect(client).to receive(:user).with(username, { headers: { 'If-None-Match' => etag } }).once

              email_for_github_username
            end
          end
        end
      end

      context 'if the email has been checked for the project' do
        before do
          Gitlab::Cache::Import::Caching.write(email_fetched_for_project_key, 1)
        end

        it 'returns nil' do
          expect(email_for_github_username).to be_nil
        end

        it_behaves_like 'does not change caches'
      end
    end
  end

  describe '#fetch_source_name_from_github' do
    let(:username) { 'kittens' }
    let(:lease_name) { "gitlab:github_import:user_finder:#{username}" }

    subject(:fetch_source_name_from_github) { finder.fetch_source_name_from_github(username) }

    it 'fetches user name from GitHub and caches it' do
      expect(finder).to receive(:in_lock).with(lease_name, sleep_sec: 0.2.seconds, retries: 30).and_call_original
      expect(client).to receive(:user).with(username).and_return({ name: 'Source name' })
      expect(Gitlab::Cache::Import::Caching).to receive(:write)
        .with(format(described_class::SOURCE_NAME_CACHE_KEY, project: project.id, username: username), 'Source name')

      expect(fetch_source_name_from_github).to eq('Source name')
    end

    context 'when lock is retried' do
      it 'returns the cached value' do
        Gitlab::Cache::Import::Caching.write(
          format(described_class::SOURCE_NAME_CACHE_KEY, project: project.id, username: username), 'Source name'
        )

        expect(finder).to receive(:in_lock).and_yield(true)

        expect(fetch_source_name_from_github).to eq('Source name')
      end
    end

    context 'when no name is returned' do
      it 'returns the username' do
        expect(client).to receive(:user).with(username).and_return({})

        expect(fetch_source_name_from_github).to eq(username)
      end
    end
  end

  describe '#cached_id_for_github_id' do
    let(:id) { 4 }

    it 'reads a user ID from the cache' do
      Gitlab::Cache::Import::Caching
        .write(described_class::ID_CACHE_KEY % id, 4)

      expect(finder.cached_id_for_github_id(id)).to eq([true, 4])
    end

    it 'reads a non existing cache key' do
      expect(finder.cached_id_for_github_id(id)).to eq([false, nil])
    end
  end

  describe '#cached_id_for_github_email' do
    let(:email) { 'kittens@example.com' }

    it 'reads a user ID from the cache' do
      Gitlab::Cache::Import::Caching
        .write(described_class::ID_FOR_EMAIL_CACHE_KEY % email, 4)

      expect(finder.cached_id_for_github_email(email)).to eq([true, 4])
    end

    it 'reads a non existing cache key' do
      expect(finder.cached_id_for_github_email(email)).to eq([false, nil])
    end
  end

  describe '#id_for_github_id' do
    let(:id) { 4 }

    before do
      allow(project).to receive(:github_enterprise_import?).and_return(false)
    end

    it 'queries and caches the user ID for a given GitHub ID' do
      expect(finder).to receive(:query_id_for_github_id)
        .with(id)
        .and_return(42)

      expect(Gitlab::Cache::Import::Caching)
        .to receive(:write)
        .with(described_class::ID_CACHE_KEY % id, 42)

      finder.id_for_github_id(id)
    end

    it 'caches a nil value if no ID could be found' do
      expect(finder).to receive(:query_id_for_github_id)
        .with(id)
        .and_return(nil)

      expect(Gitlab::Cache::Import::Caching)
        .to receive(:write)
        .with(described_class::ID_CACHE_KEY % id, nil)

      finder.id_for_github_id(id)
    end

    context 'when importing from github enterprise' do
      before do
        allow(project).to receive(:github_enterprise_import?).and_return(true)
      end

      it 'does not look up the user by external id' do
        expect(finder).not_to receive(:query_id_for_github_id)

        expect(Gitlab::Cache::Import::Caching)
          .to receive(:write)
          .with(described_class::ID_CACHE_KEY % id, nil)

        finder.id_for_github_id(id)
      end
    end
  end

  describe '#id_for_github_email' do
    let(:email) { 'kittens@example.com' }

    before do
      allow(project).to receive(:github_enterprise_import?).and_return(true)
    end

    it 'queries and caches the user ID for a given Email address' do
      expect(finder).to receive(:query_id_for_github_email)
        .with(email)
        .and_return(42)

      expect(Gitlab::Cache::Import::Caching)
        .to receive(:write)
        .with(described_class::ID_FOR_EMAIL_CACHE_KEY % email, 42)

      finder.id_for_github_email(email)
    end

    it 'caches a nil value if no ID could be found' do
      expect(finder).to receive(:query_id_for_github_email)
        .with(email)
        .and_return(nil)

      expect(Gitlab::Cache::Import::Caching)
        .to receive(:write)
        .with(described_class::ID_FOR_EMAIL_CACHE_KEY % email, nil)

      finder.id_for_github_email(email)
    end
  end

  describe '#query_id_for_github_id' do
    it 'returns the ID of the user for the given GitHub user ID' do
      user = create(:user)

      user.identities.create!(provider: :github, extern_uid: '42')

      expect(finder.query_id_for_github_id(42)).to eq(user.id)
    end

    it 'returns nil when no user ID could be found' do
      expect(finder.query_id_for_github_id(42)).to be_nil
    end
  end

  describe '#query_id_for_github_email' do
    it 'returns the ID of the user for the given Email address' do
      user = create(:user, email: 'kittens@example.com')

      expect(finder.query_id_for_github_email(user.email)).to eq(user.id)
    end

    it 'returns nil if no user ID could be found' do
      expect(finder.query_id_for_github_email('kittens@example.com')).to be_nil
    end
  end

  describe '#read_id_from_cache' do
    it 'reads an ID from the cache' do
      Gitlab::Cache::Import::Caching.write('foo', 10)

      expect(finder.read_id_from_cache('foo')).to eq([true, 10])
    end

    it 'reads a cache key with an empty value' do
      Gitlab::Cache::Import::Caching.write('foo', nil)

      expect(finder.read_id_from_cache('foo')).to eq([true, nil])
    end

    it 'reads a cache key that does not exist' do
      expect(finder.read_id_from_cache('foo')).to eq([false, nil])
    end
  end

  describe '#source_user_accepted?' do
    let!(:user) { { id: 7, login: 'anything' } }
    let!(:source_user) do
      create(
        :import_source_user, :awaiting_approval,
        namespace: project.root_ancestor,
        source_hostname: 'https://github.com',
        import_type: project.import_type,
        source_user_identifier: user[:id]
      )
    end

    it 'returns true when the associated source user has an accepted status' do
      source_user.accept!

      expect(finder.source_user_accepted?(user)).to be(true)
    end

    it 'returns false when the associated source user does not have an accepted status' do
      expect(finder.source_user_accepted?(user)).to be(false)
    end

    context 'when the project is imported into a personal namespace' do
      before do
        project.update!(namespace: user_namespace)
      end

      # User contributions are assigned directly to the namespace owner, effectively behaving as accepted source users
      it 'returns true' do
        expect(finder.source_user_accepted?(user)).to be(true)
      end

      context 'when user_mapping_to_personal_namespace_owner is disabled' do
        let(:user_mapping_to_personal_namespace_owner_enabled) { false }
        let!(:source_user) do
          create(
            :import_source_user, :awaiting_approval,
            namespace: user_namespace,
            source_hostname: 'https://github.com',
            import_type: project.import_type,
            source_user_identifier: user[:id]
          )
        end

        it 'returns false when the associated source user does not have an accepted status' do
          expect(finder.source_user_accepted?(user)).to be(false)
        end
      end
    end

    context 'when user contribution mapping is disabled' do
      let(:user_mapping_enabled) { false }

      it 'returns true' do
        expect(finder.source_user_accepted?(user)).to be(true)
      end
    end
  end
end
