Elasticsearch не синхронизируется при перегрузке по HTTP в наборе тестов

У меня есть приложение Rails с набором тестов Rspec, в котором есть некоторые тесты функций/контроллеров в зависимости от ElasticSearch.

Когда мы тестируем функцию поиска в системе (и другие функции в зависимости от ES), мы используем настоящую ES, она отлично работает в среде разработки, когда мы запускаем отдельные файлы спецификаций.

Когда пакет работает на нашем CI-сервере, он становится странным, потому что иногда ES не будет синхронизироваться достаточно быстро, чтобы тесты успешно выполнялись.

Я искал какой-то способ запустить ES в "синхронном режиме" или подождать, пока ES не будет готова, но пока ничего не нашел. Я видел некоторые обходные пути, используя Ruby sleep, но для меня это кажется неприемлемым.

Как я могу гарантировать синхронизацию ES для запуска моих тестов?

Как вы работаете с ES в своем тестовом пакете?

Вот один из моих тестов:

      context "given params page or per_page is set", :elasticsearch do

      let(:params) { {query: "Resultados", page: 1, per_page: 2} }

      before(:each) do
        3.times do |n|
          Factory(:company, account: user.account, name: "Resultados Digitais #{n}")
        end
        sync_companies_index # this is a helper method available to all specs
      end

      it "paginates the results properly" do
        get :index, params
        expect(assigns[:companies].length).to eq 2
      end

    end

Здесь мой блок настройки RSpec и ES-помощник:

RSpec.configure do |config|
  config.around :each do |example|
    if example.metadata[:elasticsearch]
      Lead.tire.index.delete # delete the index for a clean environment
      Company.tire.index.delete # delete the index for a clean environment

      example.run
    else
      FakeWeb.register_uri :any, %r(#{Tire::Configuration.url}), body: '{}'
      example.run
      FakeWeb.clean_registry
    end
  end
end

def sync_companies_index
  sync_index_of Company
end

def sync_leads_index
  sync_index_of Lead
end

def sync_index_of(klass)
  mapping = MultiJson.encode(klass.tire.mapping_to_hash, :pretty => Tire::Configuration.pretty)
  klass.tire.index.create(:mappings => klass.tire.mapping_to_hash, :settings => klass.tire.settings)
  "#{klass}::#{klass}Index".constantize.rebuild_index
  klass.index.refresh
end

Спасибо за любую помощь!

Ответ 1

Ваш тест смущен - это тестирование назначения, разбиения на страницы и (неявно) передачи параметров. Разрыв:

Параметры

let(:tire) { double('tire', :search => :sentinel) }

it 'passes the correct parameters to Companies.tire.search' do
  expected_params = ... # Some transformation, if any, of params
  Companies.stub(:tire).with(tire)
  get :index, params

  expect(tire).to have_received(:search).with(expected_params)
end

Назначение

Мы только обеспокоены тем, что код принимает одно значение и присваивает его чему-то другому, значение не имеет значения.

it 'assigns the search results to companies' do
  Companies.stub(:tire).with(tire)
  get :index, params

  expect(assigns[:companies]).to eq :sentinel
end

Разбивка

Это сложный бит. У вас нет ES API, поэтому вы не должны его заглушать, но вы также не можете использовать живой экземпляр ES, потому что вы не можете доверять ему быть надежным во всех сценариях тестирования, это просто HTTP API после все (это основной вопрос, который у вас есть). Гэри Бернхардт решил эту проблему в одном из своих превосходных screencasts - вам просто нужно подделывать вызовы HTTP. Использование видеомагнитофона:

VCR.use_cassette :tire_companies_search do
  get :index, params
  search_result_length = assigns[:companies].length

  expect(search_result_length).to eq 2
end

Запустите этот раз успешно, а затем навсегда используйте кассету (это просто файл ответа YAML). Ваши тесты больше не зависят от API, которые вы не контролируете. Если ES или ваш pagination gem обновляют свой код, просто перезапишите кассету, когда вы знаете, что API работает и работает. Существует действительно никакой другой вариант, не делающий ваши тесты чрезвычайно хрупкими или обрезающими вещи, которые вы не должны заглушить.

Обратите внимание, что хотя мы уже опустили tire, и мы не владеем им - это нормально в этих случаях, потому что возвращаемые значения совершенно не имеют отношения к тесту.