Protobuf相关的单元测试在我的本地机器上传递但在Jenkins管道中失败

时间:2018-03-30 17:13:33

标签: ruby-on-rails jenkins serialization protocol-buffers timecop

我在Rails应用程序中对序列化程序对象进行了一组单元测试。这些序列化程序对象使用google-protobuf (~> 3.5) gem,包括Google::Protobuf::Timestamp对象。对于与时间相关的属性(如purchase_order#created_atline_item#created_atinspection_event#event_occured_at),我们使用TimeSerializer对象,实现如下:

# frozen_string_literal: true

module ProtoSerializers
  class TimeSerializer < BaseProtoSerializer
    def serialize
      return if object.nil?

      GOOGLE_BASE::Timestamp.new(seconds: object&.to_i, nanos: object&.nsec)
    end
  end
end

这是通过调用ProtoSerializers::TimeSerializer.serialize(time)来实例化的,其中time是Rails Time或DateTime对象。

测试将序列化的预期结果与实际结果进行比较,如果结果匹配则通过,否则失败:

describe '#serialize an inspection whose purchase order and line item are both archived' do

  subject { described_class.serialize(object) }

  let(:purchase_order) { create(:purchase_order, :is_archived) }
  let(:line_item) { create(:line_item, :archived, purchase_order: purchase_order) }
  let(:object) { create(:inspection, line_item: line_item) }

  it 'serializes attributes' do
    expect(subject).to be_a(MyCorp::Proto::MyApp::InspectionEvent)

    expect(subject).to have_attributes(
      ...(misc key-value pairs)...
      purchase_order: ProtoSerializers::PurchaseOrderSerializer.serialize(purchase_order),
      line_item: ProtoSerializers::LineItemSerializer.serialize(line_item),
      event_occurred_at: ProtoSerializers::TimeSerializer.serialize(object.event_occurred_at)
    )
  end
end

根据标准的Rails练习,PurchaseOrderLineItem模型都具有created_at个属性。

这个测试在我的机器上传递但是当我把它推到Github(它启动Jenkins测试管道)时失败了。预期与实际差异如下:

20:00:39        -:line_item => <MyCorp::Proto::MyApp::LineItem: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710602>, ...>,
20:00:39        +:line_item => <MyCorp::Proto::MyApp::LineItem: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710000>, ...>,
20:00:39        -:purchase_order => <MyCorp::Proto::MyApp::PurchaseOrder: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710602>>,
20:00:39        +:purchase_order => <MyCorp::Proto::MyApp::PurchaseOrder: ..., created_at: <Google::Protobuf::Timestamp: seconds: 1522368034, nanos: 909710000>>,

如您所见,seconds属性匹配,但nanos attrivute关闭了几百纳秒。我已尝试在此测试中使用Timecop,如下所示,但失败的测试仍然存在:

before { Timecop.freeze(Time.now) }

after { Timecop.return }

我不确定Jenkins管道和我的机器之间有什么不同。我正在使用带有Intel Core i7处理器的Macbook,我相信它是64位的。

1 个答案:

答案 0 :(得分:0)

将我的计算机(带有Intel Core i7处理器的Macbook)上的64位整数转换为32位int纳秒的Protobufs时,原因似乎是精度下降。为了解决这个问题,我不得不嘲笑那些精确度不会降低的因素。最后我使用了Epoch时间,如下:

before { Timecop.freeze(Time.at(0)) }

after { Timecop.return }

这解决了这个问题。