Protobuf 相关的单元测试在我的本地机器上通过但在 Jenkins 管道中失败
Protobuf-related unit tests passing on my local machine but failing in Jenkins pipeline
我的 Rails 应用程序中有一组序列化程序对象的单元测试。这些序列化器对象使用 google-protobuf (~> 3.5)
gem,包括 Google::Protobuf::Timestamp
对象。对于与时间相关的属性(如 purchase_order#created_at
、line_item#created_at
和 inspection_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 时间或日期时间对象。
测试将序列化的预期结果与实际结果进行比较,如果结果匹配则通过,否则失败:
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
PurchaseOrder
和 LineItem
模型都具有 created_at
属性,根据标准 Rails 实践。
这个测试在我的机器上通过了,但是当我将它推到 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
属性相差几百纳秒。我已经尝试在此测试中使用 Timecop,如下所示,但失败的测试仍然存在:
before { Timecop.freeze(Time.now) }
after { Timecop.return }
我不确定 Jenkins 管道和我的机器之间有什么不同。我正在使用配备 Intel Core i7 处理器的 Macbook,我认为它是 64 位的。
看来原因是在我的机器(配备 Intel Core i7 处理器的 Macbook)上将 64 位整数转换为 Protobufs 32 位整数纳秒时精度损失。为了解决这个问题,我不得不将时间模拟到精度损失不会成为一个因素的地方。最后我用的是Epoch时间,如下:
before { Timecop.freeze(Time.at(0)) }
after { Timecop.return }
这解决了问题。
我的 Rails 应用程序中有一组序列化程序对象的单元测试。这些序列化器对象使用 google-protobuf (~> 3.5)
gem,包括 Google::Protobuf::Timestamp
对象。对于与时间相关的属性(如 purchase_order#created_at
、line_item#created_at
和 inspection_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 时间或日期时间对象。
测试将序列化的预期结果与实际结果进行比较,如果结果匹配则通过,否则失败:
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
PurchaseOrder
和 LineItem
模型都具有 created_at
属性,根据标准 Rails 实践。
这个测试在我的机器上通过了,但是当我将它推到 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
属性相差几百纳秒。我已经尝试在此测试中使用 Timecop,如下所示,但失败的测试仍然存在:
before { Timecop.freeze(Time.now) }
after { Timecop.return }
我不确定 Jenkins 管道和我的机器之间有什么不同。我正在使用配备 Intel Core i7 处理器的 Macbook,我认为它是 64 位的。
看来原因是在我的机器(配备 Intel Core i7 处理器的 Macbook)上将 64 位整数转换为 Protobufs 32 位整数纳秒时精度损失。为了解决这个问题,我不得不将时间模拟到精度损失不会成为一个因素的地方。最后我用的是Epoch时间,如下:
before { Timecop.freeze(Time.at(0)) }
after { Timecop.return }
这解决了问题。