diff --git a/Gemfile b/Gemfile index 052aa375..6f7fe5e2 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gemspec group :development, :test do gem 'connection_pool' + gem 'debug' gem 'minitest', '~> 5' gem 'rack', '~> 2.0', '>= 2.2.0' gem 'rake', '~> 13.0' diff --git a/lib/dalli.rb b/lib/dalli.rb index ad05e3b3..d53ab599 100644 --- a/lib/dalli.rb +++ b/lib/dalli.rb @@ -27,6 +27,9 @@ class ValueOverMaxSize < DalliError; end # operation is not permitted in a multi block class NotPermittedMultiOpError < DalliError; end + # raised when Memcached response with a SERVER_ERROR + class ServerError < DalliError; end + # Implements the NullObject pattern to store an application-defined value for 'Key not found' responses. class NilObject; end # rubocop:disable Lint/EmptyClass NOT_FOUND = NilObject.new diff --git a/lib/dalli/protocol/meta/response_processor.rb b/lib/dalli/protocol/meta/response_processor.rb index c552b3ea..5fc3c1a8 100644 --- a/lib/dalli/protocol/meta/response_processor.rb +++ b/lib/dalli/protocol/meta/response_processor.rb @@ -21,6 +21,7 @@ class ResponseProcessor STAT = 'STAT' VA = 'VA' VERSION = 'VERSION' + SERVER_ERROR = 'SERVER_ERROR' def initialize(io_source, value_marshaller) @io_source = io_source @@ -167,9 +168,12 @@ def header_from_buffer(buf) def error_on_unexpected!(expected_codes) tokens = next_line_to_tokens - raise Dalli::DalliError, "Response error: #{tokens.first}" unless expected_codes.include?(tokens.first) - tokens + return tokens if expected_codes.include?(tokens.first) + + raise Dalli::ServerError, tokens.join(' ').to_s if tokens.first == SERVER_ERROR + + raise Dalli::DalliError, "Response error: #{tokens.first}" end def bitflags_from_tokens(tokens) diff --git a/test/integration/test_network.rb b/test/integration/test_network.rb index bc1fe8a3..9b9c3cf1 100644 --- a/test/integration/test_network.rb +++ b/test/integration/test_network.rb @@ -361,4 +361,19 @@ end end end + + if MemcachedManager.supported_protocols.include?(:meta) + describe 'ServerError' do + it 'is raised when Memcached response with a SERVER_ERROR' do + memcached_mock(->(sock) { sock.write("SERVER_ERROR foo bar\r\n") }) do + dc = Dalli::Client.new('localhost:19123', protocol: :meta) + err = assert_raises Dalli::ServerError do + dc.get('abc') + end + + assert_equal 'SERVER_ERROR foo bar', err.message + end + end + end + end end