在测试套件上的HTTP不堪重负时,Elasticsearch不同步

luc*_*ins 12 ruby rspec ruby-on-rails elasticsearch

我有一个带有Rspec测试套件的Rails应用程序,它具有一些功能/控制器测试,具体取决于ElasticSearch.

当我们测试系统周围的"搜索"功能(以及依赖于ES的其他功能)时,我们使用真正的ES,当我们运行单个spec文件时,它在开发环境中完美运行.

当套件在我们的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
Run Code Online (Sandbox Code Playgroud)

这是我的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
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

SLD*_*SLD 9

您的测试很困惑 - 它正在测试分配,分页和(隐式)参数传递.打破它:

参数

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
Run Code Online (Sandbox Code Playgroud)

分配

我们只担心代码占用一个值并将其分配给其他值,这个值是无关紧要的.

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

  expect(assigns[:companies]).to eq :sentinel
end
Run Code Online (Sandbox Code Playgroud)

分页

这是棘手的一点.您不拥有ES API,因此您不应该使用它,但您也不能使用ES的实例,因为您不能相信它在所有测试场景中都是可靠的,它只是一个HTTP API之后所有(这是你所拥有的根本问题).Gary Bernhardt在他的一个优秀的截屏视频中解决了这个问题- 你只需要伪造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
Run Code Online (Sandbox Code Playgroud)

成功运行一次然后永远更多地使用盒式磁带(这只是响应的YAML文件).您的测试不再依赖于您无法控制的API.如果ES或您的分页宝石更新其代码,只需在您知道API已启动并正常工作时重新录制磁带.没有任何其他选择,如果你的测试非常脆弱,或者你不应该存根.

请注意,虽然我们tire上面已经存在- 而且我们没有它 - 但在这些情况下它是正常的,因为返回值与测试完全无关.