Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/mongo/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def change_stream_resumable?
TRANSIENT_TRANSACTION_ERROR_LABEL = 'TransientTransactionError'.freeze

def initialize(msg = nil)
@labels = []
@labels ||= []
super(msg)
end

Expand All @@ -114,6 +114,18 @@ def label?(label)
@labels.include?(label)
end

# Gets the set of labels associated with the error.
#
# @example
# error.labels
#
# @return [ Array ] The set of labels.
#
# @since 2.7.0
def labels
@labels.dup
end

private

def add_label(label)
Expand Down
1 change: 1 addition & 0 deletions lib/mongo/error/operation_failure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def initialize(message = nil, result = nil, options = {})
@result = result
@code = options[:code]
@code_name = options[:code_name]
@labels = options[:labels]
super(message)
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/mongo/error/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class Parser
# @since 2.6.0
attr_reader :code_name

# @return [ Array ] labels The set of labels associated with the error.
# @since 2.7.0
attr_reader :labels

# Create the new parser with the returned document.
#
# @example Create the new parser.
Expand All @@ -88,6 +92,7 @@ def parse!
document[WRITE_CONCERN_ERROR]) if document[WRITE_CONCERN_ERROR]
parse_flag(@message)
parse_code
parse_labels
end

def parse_single(message, key, doc = document)
Expand Down Expand Up @@ -147,6 +152,10 @@ def parse_code
end
end
end

def parse_labels
@labels = document['errorLabels'] || []
end
end
end
end
14 changes: 13 additions & 1 deletion lib/mongo/operation/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def raise_operation_failure
raise Error::OperationFailure.new(
parser.message,
self,
:code => parser.code, :code_name => parser.code_name)
:code => parser.code, :code_name => parser.code_name, :labels => parser.labels)
end
private :raise_operation_failure

Expand Down Expand Up @@ -312,6 +312,18 @@ def cluster_time
first_document && first_document[CLUSTER_TIME]
end

# Gets the set of error labels associated with the result.
#
# @example Get the labels.
# result.labels
#
# @return [ Array ] labels The set of labels.
#
# @since 2.7.0
def labels
@labels ||= parser.labels
end

private

def aggregate_returned_count
Expand Down
70 changes: 70 additions & 0 deletions spec/mongo/error/operation_failure_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,74 @@
end
end
end

describe '#labels' do

context 'when the result is nil' do

subject do
described_class.new('not master (10107)', nil,
:code => 10107, :code_name => 'NotMaster')
end

it 'has no labels' do
expect(subject.labels).to eq([])
end
end

context 'when the result is not nil' do

let(:reply_document) do
{
'code' => 251,
'codeName' => 'NoSuchTransaction',
'errorLabels' => labels,
}
end

let(:reply) do
Mongo::Protocol::Reply.new.tap do |r|
# Because this was not created by Mongo::Protocol::Reply::deserialize, we need to manually
# initialize the fields.
r.instance_variable_set(:@documents, [reply_document])
r.instance_variable_set(:@flags, [])
end
end

let(:result) do
Mongo::Operation::Result.new(reply)
end

subject do
begin
result.send(:raise_operation_failure)
rescue => e
e
end
end

context 'when the error has no labels' do

let(:labels) do
[]
end

it 'has the correct labels' do
expect(subject.labels).to eq(labels)
end
end


context 'when the error has labels' do

let(:labels) do
[ Mongo::Error::TRANSIENT_TRANSACTION_ERROR_LABEL ]
end

it 'has the correct labels' do
expect(subject.labels).to eq(labels)
end
end
end
end
end
54 changes: 44 additions & 10 deletions spec/mongo/error/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
end
end
end

describe '#code' do
let(:parser) do
described_class.new(document)
Expand All @@ -105,7 +105,7 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master', 'code' => 10107, 'codeName' => 'NotMaster' }
end

it 'returns the code' do
expect(parser.code).to eq(10107)
end
Expand All @@ -115,7 +115,7 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master' }
end

it 'returns nil' do
expect(parser.code).to eq(nil)
end
Expand Down Expand Up @@ -143,7 +143,7 @@
end
end
end

describe '#code_name' do
let(:parser) do
described_class.new(document)
Expand All @@ -153,7 +153,7 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master', 'code' => 10107, 'codeName' => 'NotMaster' }
end

it 'returns the code name' do
expect(parser.code_name).to eq('NotMaster')
end
Expand All @@ -163,7 +163,7 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master' }
end

it 'returns nil' do
expect(parser.code_name).to eq(nil)
end
Expand Down Expand Up @@ -192,7 +192,7 @@
end
end
end

describe '#document' do
let(:parser) do
described_class.new(document)
Expand All @@ -201,12 +201,12 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master', 'code' => 10107, 'codeName' => 'NotMaster' }
end

it 'returns the document' do
expect(parser.document).to eq(document)
end
end

describe '#replies' do
let(:parser) do
described_class.new(document)
Expand All @@ -216,10 +216,44 @@
let(:document) do
{ 'ok' => 0, 'errmsg' => 'not master', 'code' => 10107, 'codeName' => 'NotMaster' }
end

it 'returns nil' do
expect(parser.replies).to eq(nil)
end
end
end

describe '#labels' do
let(:parser) do
described_class.new(document)
end

let(:document) do
{
'code' => 251,
'codeName' => 'NoSuchTransaction',
'errorLabels' => labels,
}
end

context 'when there are no labels' do
let(:labels) do
[]
end

it 'has the correct labels' do
expect(parser.labels).to eq(labels)
end
end

context 'when there are labels' do
let(:labels) do
[ Mongo::Error::TRANSIENT_TRANSACTION_ERROR_LABEL ]
end

it 'has the correct labels' do
expect(parser.labels).to eq(labels)
end
end
end
end
4 changes: 2 additions & 2 deletions spec/support/transactions/operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ def execute(collection, session0, session1)
{
'errorCodeName' => err_doc['codeName'] || err_doc['writeConcernError']['codeName'],
'errorContains' => e.message,
'errorLabels' => (e.instance_variable_get(:@labels) || []) + (err_doc['errorLabels'] || [])
'errorLabels' => e.labels
}
rescue Mongo::Error => e
{
'errorContains' => e.message,
'errorLabels' => e.instance_variable_get(:@labels) || []
'errorLabels' => e.labels
}
end

Expand Down