请求规范顺序相关失败(为登录时设计用户更新创建了错误的 SQL)

Request spec order dependent failure (wrong SQL created for devise user update on login)

我们目前面临一个问题,当一个请求规范失败(拼写错误或其他异常)时,它会影响其他实际上应该不受影响的请求规范。问题是我们使用了很多 gem,所以我尝试创建一个最小的复制应用程序(没有成功,https://github.com/tak1n/reproduction

问题详细:

我们有一个需要登录用户的请求规范。对于用户身份验证,我们使用设计,因此我们使用 Warden::Test::Helpers 在请求规范中登录用户。 Devise 在用户登录时自动更新一些与用户相关的属性(last_sign_in_at、last_sign_in_ip 等)。

这里的问题是,当它试图保存执行此更改的用户时,最终结果是 INSERT INTO 用户而不是 UPDATE 用户,因此它崩溃了。

这是我们应用程序的示例规范:

require 'rails_helper'

RSpec.describe 'Suggestions API' do
  let(:user) { FactoryGirl.create(:user, :professional) }

  before do
    login(user) # same as in https://github.com/tak1n/reproduction/blob/master/spec/support/request_macros.rb#L6
  end

  describe '/suggestions.json', :vcr do
    context 'with non saved filter' do
      # some setup stuff here (setup proper objects in db)

      # also params are defined here through let(:params) { ... }

      it 'returns proper suggestions' do
        Suggestion.refresh!

        get '/suggestions.json', paramst

        expect(json.count).to eq(2)

        expect(json.first['id']).to eq(sug2.id)
        expect(json.second['id']).to eq(sug1.id)
      end
    end

    context 'with saved filter' do
      # some setup stuff here (setup proper objects in db)

      # also params are defined here through let(:params) { ... }

      it 'returns proper suggestions' do
        Suggestion.refresh!

        get '/suggestions.json', params

        expect(json.count).to eq(2)

        expect(json.first['id']).to eq(sug2.id)
        expect(json.second['id']).to eq(sug1.id)
      end
    end
  end
end

这样做的结果应该是第一个规范由于错字 paramst 而失败,但它也影响了第二个规范:

这是规范 运行:https://gist.github.com/tak1n/102c1aa121b66e0ab56602b76f911ec0

我试图深入挖掘,发现保存创建或更新记录的逻辑取决于https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb#L85

接下来我尝试输出 @new_record 在那种情况下的结果。

def new_record?
  sync_with_transaction_state
  puts "New record: #{@new_record}" if self.class == User
  @new_record
end

我得到以下信息:https://gist.github.com/tak1n/330560a3a108abc8fce4d105a48ac444

当规格 运行 以不同的顺序排列时(首先没有失败,然后是有拼写错误或异常的规格)我得到了这个:https://gist.github.com/tak1n/6eb24693226d8e6a713c0865ea1bebd5

此处的区别是 "working" 规范 运行 New Record: <boolean> 不同。当在新记录之前有异常 运行s 的规范突然变为真,因此它生成 SQL 以创建新记录。

接下来我假设一些 gem 导致了这个问题,很可能我认为它会是 database_cleaner 但在复制品中我或多或少做了同样的事情并且它起作用了。

问题是我一直在调试,不知道从哪里开始。我也不确定是哪个 gem 或我们的代码本身导致了这个问题。

如果您需要更多详细信息,请随时提出任何问题,在此先感谢。

问题似乎是由设计异步引起的 (https://github.com/mhfs/devise-async)。

有关详细信息,请参阅 https://github.com/rails/rails/issues/26038 and https://github.com/mhfs/devise-async/issues/96