diff --git a/.gitignore b/.gitignore index 4040c6c..2f0a9ac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .bundle Gemfile.lock pkg/* +.DS_Store diff --git a/lib/orient_db_client.rb b/lib/orient_db_client.rb index 30090f9..f51609f 100644 --- a/lib/orient_db_client.rb +++ b/lib/orient_db_client.rb @@ -11,9 +11,9 @@ def connect(host, options = {}) s = TCPSocket.open(host, options[:port]) - protocol = s.read(2).unpack('s>').first + protocol = BinData::Int16be.read(s) - Connection.new(s, protocol) + Connection.new(s, options[:protocol] || protocol) end module_function :connect end diff --git a/lib/orient_db_client/network_message.rb b/lib/orient_db_client/network_message.rb index b91f745..58017ad 100644 --- a/lib/orient_db_client/network_message.rb +++ b/lib/orient_db_client/network_message.rb @@ -1,5 +1,8 @@ +require "bindata" + module OrientDbClient class NetworkMessage + def initialize(&block) @components = [] diff --git a/lib/orient_db_client/protocol_factory.rb b/lib/orient_db_client/protocol_factory.rb index ff61832..0e47931 100644 --- a/lib/orient_db_client/protocol_factory.rb +++ b/lib/orient_db_client/protocol_factory.rb @@ -4,9 +4,15 @@ module OrientDbClient class ProtocolFactory + # Orient server 1.0 supports Protocols 7 and 9. + # Since Protocols 10 and 11 are not implemented by this client, + # protocol 9 is substituted to allow connections to succeed. + PROTOCOLS = { '7' => Protocols::Protocol7, - '9' => Protocols::Protocol9 + '9' => Protocols::Protocol9, + '10' => Protocols::Protocol9, + '11' => Protocols::Protocol9 } def self.get_protocol(version) diff --git a/lib/orient_db_client/protocols/.DS_Store b/lib/orient_db_client/protocols/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/lib/orient_db_client/protocols/.DS_Store and /dev/null differ diff --git a/lib/orient_db_client/protocols/protocol7.rb b/lib/orient_db_client/protocols/protocol7.rb index 8a932e7..47a6016 100644 --- a/lib/orient_db_client/protocols/protocol7.rb +++ b/lib/orient_db_client/protocols/protocol7.rb @@ -4,6 +4,8 @@ require 'orient_db_client/serializers/serializer7' require 'orient_db_client/exceptions' +require 'bindata' + module OrientDbClient module Protocols class Protocol7 @@ -71,6 +73,227 @@ module VersionControl NEW_SESSION = -1 + class ProtocolString < BinData::Primitive + endian :big + + int32 :len, :value => lambda { data.length } + string :data, :read_length => :len + + def get; self.data; end + def set(v) self.data = v; end + end + + class QueryMessage < BinData::Record + endian :big + + protocol_string :query_class_name + protocol_string :text + int32 :non_text_limit, :initial_value => -1 + int32 :serialized_params, :value => 0 + end + + module Commands + class Command < BinData::Record + endian :big + + int8 :operation, :value => Operations::COMMAND + int32 :session + int8 :mode, :initial_value => 's'.ord + + protocol_string :command_serialized + end + + class Connect < BinData::Record + endian :big + + int8 :operation, :value => Operations::CONNECT + int32 :session, :value => NEW_SESSION + protocol_string :driver, :value => DRIVER_NAME + protocol_string :driver_version, :value => DRIVER_VERSION + int16 :version + protocol_string :client_id + protocol_string :user + protocol_string :password + end + + class Count < BinData::Record + endian :big + + int8 :operation, :value => Operations::COUNT + int32 :session + protocol_string :cluster_name + end + + class DataclusterAddLogical < BinData::Record + endian :big + + int8 :operation, :value => Operations::DATACLUSTER_ADD + int32 :session + protocol_string :type, :value => 'LOGICAL' + + int32 :physical_cluster_container_id + end + + class DataclusterAddMemory < BinData::Record + endian :big + + int8 :operation, :value => Operations::DATACLUSTER_ADD + int32 :session + protocol_string :type, :value => 'MEMORY' + + protocol_string :name + end + + class DataclusterAddPhysical < BinData::Record + endian :big + + int8 :operation, :value => Operations::DATACLUSTER_ADD + int32 :session + protocol_string :type, :value => 'PHYSICAL' + + protocol_string :name + protocol_string :file_name + int32 :initial_size, :initial_value => -1 + end + + class DataclusterDatarange < BinData::Record + endian :big + + int8 :operation, :value => Operations::DATACLUSTER_DATARANGE + int32 :session + int16 :cluster_id + end + + class DataclusterRemove < BinData::Record + endian :big + + int8 :operation, :value => Operations::DATACLUSTER_REMOVE + int32 :session + Int16 :cluster_id + end + + class DbClose < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_CLOSE + int32 :session + end + + class DbCountRecords < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_COUNTRECORDS + int32 :session + end + + class DbCreate < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_CREATE + int32 :session + + protocol_string :database + protocol_string :storage_type + end + + class DbDelete < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_DELETE + int32 :session + + protocol_string :database + end + + class DbExist < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_EXIST + int32 :session + + protocol_string :database + end + + class DbOpen < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_OPEN + int32 :session, :value => NEW_SESSION + + protocol_string :driver, :value => DRIVER_NAME + protocol_string :driver_version, :value => DRIVER_VERSION + int16 :version + protocol_string :client_id + protocol_string :database + protocol_string :user + protocol_string :password + end + + class DbReload < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_RELOAD + int32 :session + end + + class DbSize < BinData::Record + endian :big + + int8 :operation, :value => Operations::DB_SIZE + int32 :session + end + + class RecordCreate < BinData::Record + endian :big + + int8 :operation, :value => Operations::RECORD_CREATE + int32 :session + + int16 :cluster_id + protocol_string :record_content + int8 :record_type, :value => RecordTypes::DOCUMENT + int8 :mode, :value => SyncModes::SYNC + end + + class RecordDelete < BinData::Record + endian :big + + int8 :operation, :value => Operations::RECORD_DELETE + int32 :session + + int16 :cluster_id + int64 :cluster_position + int32 :record_version + int8 :mode, :value => SyncModes::SYNC + end + + class RecordLoad < BinData::Record + endian :big + + int8 :operation, :value => Operations::RECORD_LOAD + int32 :session + + int16 :cluster_id + int64 :cluster_position + protocol_string :fetch_plan + end + + class RecordUpdate < BinData::Record + endian :big + + int8 :operation, :value => Operations::RECORD_UPDATE + int32 :session + + int16 :cluster_id + int64 :cluster_position + + protocol_string :record_content + int32 :record_version + int8 :record_type, :value => RecordTypes::DOCUMENT + int8 :mode, :value => SyncModes::SYNC + end + end + def self.command(socket, session, command, options = {}) options = { :async => false, # Async mode is not supported yet @@ -86,19 +309,15 @@ def self.command(socket, session, command, options = {}) end end - serialized_command = NetworkMessage.new { |m| - m.add :string, options[:query_class_name] - m.add :string, command - m.add :integer, options[:non_text_limit] || options[:limit] - m.add :integer, 0 - }.pack + query = QueryMessage.new :query_class_name => options[:query_class_name], + :text => command, + :non_text_limit => options[:non_text_limit] || options[:limit] + + command = Commands::Command.new :session => session, + :mode => options[:async] ? 'a'.ord : 's'.ord, + :command_serialized => query.to_binary_s - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::COMMAND - m.add :integer, session - m.add :byte, options[:async] ? 'a' : 's' - m.add :string, serialized_command - }.pack + command.write(socket) read_response(socket) @@ -107,16 +326,10 @@ def self.command(socket, session, command, options = {}) end def self.connect(socket, options = {}) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::CONNECT - m.add :integer, NEW_SESSION - m.add :string, DRIVER_NAME - m.add :string, DRIVER_VERSION - m.add :short, self.version - m.add :integer, 0 - m.add :string, options[:user] - m.add :string, options[:password] - }.pack + command = Commands::Connect.new :version => self.version, + :user => options[:user], + :password => options[:password] + command.write(socket) read_response(socket) @@ -125,11 +338,10 @@ def self.connect(socket, options = {}) end def self.count(socket, session, cluster_name) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::COUNT - m.add :integer, session - m.add :string, cluster_name - }.pack + command = Commands::Count.new :session => session, + :cluster_name => cluster_name + + command.write(socket) read_response(socket) @@ -138,25 +350,23 @@ def self.count(socket, session, cluster_name) end def self.datacluster_add(socket, session, type, options) - socket.write NetworkMessage.new { |m| - type = type.downcase.to_sym if type.is_a?(String) - type_string = type.to_s.upcase - - m.add :byte, Operations::DATACLUSTER_ADD - m.add :integer, session - m.add :string, type_string - - case type - when :physical - m.add :string, options[:name] - m.add :string, options[:file_name] - m.add :integer, options[:initial_size] || -1 - when :logical - m.add :integer, options[:physical_cluster_container_id] - when :memory - m.add :string, options[:name] - end - }.pack + type = type.downcase.to_sym if type.is_a?(String) + + case type + when :physical + command = Commands::DataclusterAddPhysical.new :session => session, + :name => options[:name], + :file_name => options[:file_name], + :initial_size => options[:initial_size] || -1 + when :logical + command = Commands::DataclusterAddLogical.new :session => session, + :physical_cluster_container_id => options[:physical_cluster_container_id] + when :memory + command = Commands::DataclusterAddMemory.new :session => session, + :name => options[:name] + end + + command.write(socket) read_response(socket) @@ -165,11 +375,10 @@ def self.datacluster_add(socket, session, type, options) end def self.datacluster_datarange(socket, session, cluster_id) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DATACLUSTER_DATARANGE - m.add :integer, session - m.add :short, cluster_id - }.pack + command = Commands::DataclusterDatarange.new :session => session, + :cluster_id => cluster_id + + command.write(socket) read_response(socket) @@ -178,11 +387,9 @@ def self.datacluster_datarange(socket, session, cluster_id) end def self.datacluster_remove(socket, session, cluster_id) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DATACLUSTER_REMOVE - m.add :integer, session - m.add :short, cluster_id - }.pack + command = Commands::DataclusterRemove.new :session => session, + :cluster_id => cluster_id + command.write(socket) read_response(socket) @@ -191,19 +398,15 @@ def self.datacluster_remove(socket, session, cluster_id) end def self.db_close(socket, session = NEW_SESSION) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_CLOSE - m.add :integer, session - }.pack + command = Commands::DbClose.new :session => session + command.write(socket) return socket.closed? end def self.db_countrecords(socket, session) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_COUNTRECORDS - m.add :integer, session - }.pack + command = Commands::DbCountRecords.new :session => session + command.write(socket) read_response(socket) @@ -220,7 +423,7 @@ def self.db_create(socket, session, database, options = {}) options[:storage_type] = options[:storage_type].to_s - socket.write make_db_create_message(session, database, options).pack + make_db_create_command(session, database, options).write(socket) read_response(socket) @@ -228,11 +431,9 @@ def self.db_create(socket, session, database, options = {}) end def self.db_delete(socket, session, database) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_DELETE - m.add :integer, session - m.add :string, database - }.pack + command = Commands::DbDelete.new :session => session, + :database => database + command.write(socket) read_response(socket) @@ -240,11 +441,9 @@ def self.db_delete(socket, session, database) end def self.db_exist(socket, session, database) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_EXIST - m.add :integer, session - m.add :string, database - }.pack + command = Commands::DbExist.new :session => session, + :database => database + command.write(socket) read_response(socket) @@ -253,17 +452,11 @@ def self.db_exist(socket, session, database) end def self.db_open(socket, database, options = {}) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_OPEN - m.add :integer, NEW_SESSION - m.add :string, DRIVER_NAME - m.add :string, DRIVER_VERSION - m.add :short, self.version - m.add :integer, 0 - m.add :string, database - m.add :string, options[:user] - m.add :string, options[:password] - }.pack + command = Commands::DbOpen.new :version => self.version, + :database => database, + :user => options[:user], + :password => options[:password] + command.write(socket) read_response(socket) @@ -272,10 +465,8 @@ def self.db_open(socket, database, options = {}) end def self.db_reload(socket, session) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_RELOAD - m.add :integer, session - }.pack + command = Commands::DbReload.new :session => session + command.write(socket) read_response(socket) @@ -284,10 +475,8 @@ def self.db_reload(socket, session) end def self.db_size(socket, session) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_SIZE - m.add :integer, session - }.pack + command = Commands::DbSize.new :session => session + command.write(socket) read_response(socket) @@ -296,14 +485,10 @@ def self.db_size(socket, session) end def self.record_create(socket, session, cluster_id, record) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::RECORD_CREATE - m.add :integer, session - m.add :short, cluster_id - m.add :string, serializer.serialize(record) - m.add :byte, RecordTypes::DOCUMENT - m.add :byte, SyncModes::SYNC - }.pack + command = Commands::RecordCreate.new :session => session, + :cluster_id => cluster_id, + :record_content => serializer.serialize(record) + command.write(socket) read_response(socket) @@ -312,14 +497,11 @@ def self.record_create(socket, session, cluster_id, record) end def self.record_delete(socket, session, cluster_id, cluster_position, version) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::RECORD_DELETE - m.add :integer, session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :integer, version - m.add :byte, SyncModes::SYNC - }.pack + command = Commands::RecordDelete.new :session => session, + :cluster_id => cluster_id, + :cluster_position => cluster_position, + :record_version => version + command.write(socket) read_response(socket) @@ -328,13 +510,10 @@ def self.record_delete(socket, session, cluster_id, cluster_position, version) end def self.record_load(socket, session, rid) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::RECORD_LOAD - m.add :integer, session - m.add :short, rid.cluster_id - m.add :long, rid.cluster_position - m.add :string, "" - }.pack + command = Commands::RecordLoad.new :session => session, + :cluster_id => rid.cluster_id, + :cluster_position => rid.cluster_position + command.write(socket) read_response(socket) @@ -351,16 +530,12 @@ def self.record_update(socket, session, cluster_id, cluster_position, record, ve end end - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::RECORD_UPDATE - m.add :integer, session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :string, serializer.serialize(record) - m.add :integer, version - m.add :byte, RecordTypes::DOCUMENT - m.add :byte, SyncModes::SYNC - }.pack + command = Commands::RecordUpdate.new :session => session, + :cluster_id => cluster_id, + :cluster_position => cluster_position, + :record_content => serializer.serialize(record), + :record_version => version + command.write(socket) read_response(socket) @@ -382,21 +557,18 @@ def self.version private - def self.make_db_create_message(*args) + def self.make_db_create_command(*args) session = args.shift database = args.shift options = args.shift - NetworkMessage.new { |m| - m.add :byte, Operations::DB_CREATE - m.add :integer, session - m.add :string, database - m.add :string, options[:storage_type].to_s - } + Commands::DbCreate.new :session => session, + :database => database, + :storage_type => options[:storage_type] end def self.read_byte(socket) - socket.read(1).unpack('C').first + BinData::Int8.read(socket).to_i end def self.read_count(socket) @@ -492,11 +664,11 @@ def self.read_db_size(socket) end def self.read_integer(socket) - socket.read(4).unpack('l>').first + BinData::Int32be.read(socket).to_i end def self.read_long(socket) - socket.read(8).unpack('q>').first + BinData::Int64be.read(socket).to_i end def self.read_record(socket) @@ -579,13 +751,17 @@ def self.raise_response_error(socket) end def self.read_short(socket) - socket.read(2).unpack('s>').first + BinData::Int16be.read(socket).to_i end def self.read_string(socket) - length = read_integer(socket) - - length > 0 ? socket.read(length) : nil + bin_length = read_integer(socket) + return nil if bin_length < 0 + + raise bin_length.inspect if bin_length < 0 + + bin_str = socket.read(bin_length) + bin_str.length > 0 ? bin_str : nil end end end diff --git a/lib/orient_db_client/protocols/protocol9.rb b/lib/orient_db_client/protocols/protocol9.rb index 8caab4d..eb0eee9 100644 --- a/lib/orient_db_client/protocols/protocol9.rb +++ b/lib/orient_db_client/protocols/protocol9.rb @@ -1,94 +1,125 @@ require 'orient_db_client/network_message' require 'orient_db_client/version' -module OrientDbClient - module Protocols - class Protocol9 < Protocol7 - VERSION = 9 - - def self.command(socket, session, command, options = {}) - options[:query_class_name].tap do |qcn| - if qcn.is_a?(Symbol) - qcn = case qcn - when :query then 'q' - when :command then 'c' - end - end - - if qcn.nil? || qcn == 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery' - qcn = 'q' - end - - options[:query_class_name] = qcn - end - - super socket, session, command, options - end +require 'bindata' - def self.db_create(socket, session, database, options = {}) - if options.is_a?(String) - options = { :storage_type => options } - end +module OrientDbClient + module Protocols + class Protocol9 < Protocol7 + VERSION = 9 - options = { - :database_type => 'document' - }.merge(options) + module Commands + class DbCreate9 < BinData::Record + endian :big - super - end + int8 :operation, :value => Protocol7::Operations::DB_CREATE + int32 :session - def self.db_open(socket, database, options = {}) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::DB_OPEN - m.add :integer, NEW_SESSION - m.add :string, DRIVER_NAME - m.add :string, DRIVER_VERSION - m.add :short, self.version - m.add :integer, 0 - m.add :string, database - m.add :string, options[:database_type] || "document" - m.add :string, options[:user] - m.add :string, options[:password] - }.pack - - read_response(socket) - - { :session => read_integer(socket), - :message_content => read_db_open(socket) } - end + protocol_string :database + protocol_string :database_type + protocol_string :storage_type + end - def self.record_load(socket, session, rid, options = {}) - socket.write NetworkMessage.new { |m| - m.add :byte, Operations::RECORD_LOAD - m.add :integer, session - m.add :short, rid.cluster_id - m.add :long, rid.cluster_position - m.add :string, "" - m.add :byte, options[:ignore_cache] === true ? 1 : 0 - }.pack + class DbOpen9 < BinData::Record + endian :big - read_response(socket) + int8 :operation, :value => Protocol7::Operations::DB_OPEN + int32 :session, :value => Protocol7::NEW_SESSION - { :session => read_integer(socket), - :message_content => read_record_load(socket) } - end + protocol_string :driver_name, :value => Protocol7::DRIVER_NAME + protocol_string :driver_version, :value => Protocol7::DRIVER_VERSION + int16 :protocol_version + protocol_string :client_id + protocol_string :database_name + protocol_string :database_type + protocol_string :user_name + protocol_string :user_password + end - private + class RecordLoad9 < BinData::Record + endian :big - def self.make_db_create_message(*args) - session = args.shift - database = args.shift - options = args.shift + int8 :operation, :value => Protocol7::Operations::RECORD_LOAD + int32 :session - NetworkMessage.new { |m| - m.add :byte, Operations::DB_CREATE - m.add :integer, session - m.add :string, database - m.add :string, options[:database_type].to_s - m.add :string, options[:storage_type].to_s - } + int16 :cluster_id + int64 :cluster_position + protocol_string :fetch_plan + int8 :ignore_cache, :initial_value => 0 + end + end + + def self.command(socket, session, command, options = {}) + options[:query_class_name].tap do |qcn| + if qcn.is_a?(Symbol) + qcn = case qcn + when :query then 'q' + when :command then 'c' end + end + if qcn.nil? || qcn == 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery' + qcn = 'q' + end + + options[:query_class_name] = qcn end + + super socket, session, command, options + end + + def self.db_create(socket, session, database, options = {}) + if options.is_a?(String) + options = { :storage_type => options } + end + + options = { + :database_type => 'document' + }.merge(options) + + super + end + + def self.db_open(socket, database, options = {}) + command = Commands::DbOpen9.new :protocol_version => self.version, + :database_name => database, + :database_type => options[:database_type] || 'document', + :user_name => options[:user], + :user_password => options[:password] + command.write(socket) + + read_response(socket) + + { :session => read_integer(socket), + :message_content => read_db_open(socket) } + end + + def self.record_load(socket, session, rid, options = {}) + command = Commands::RecordLoad9.new :session => session, + :cluster_id => rid.cluster_id, + :cluster_position => rid.cluster_position, + :ignore_cache => options[:ignore_cache] === true ? 1 : 0 + command.write(socket) + + read_response(socket) + + { :session => read_integer(socket), + :message_content => read_record_load(socket) } + end + + private + + def self.make_db_create_command(*args) + session = args.shift + database = args.shift + options = args.shift + + Commands::DbCreate9.new :session => session, + :database => database, + :database_type => options[:database_type].to_s, + :storage_type => options[:storage_type] + end + end + end end \ No newline at end of file diff --git a/orient_db_client.gemspec b/orient_db_client.gemspec index d657a63..030cac9 100644 --- a/orient_db_client.gemspec +++ b/orient_db_client.gemspec @@ -18,6 +18,8 @@ Gem::Specification.new do |s| s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] + s.add_dependency "bindata" + s.add_development_dependency "minitest" s.add_development_dependency "mocha" s.add_development_dependency "rake" diff --git a/test/support/connection_helper.rb b/test/support/connection_helper.rb index df513ad..5a77cb7 100644 --- a/test/support/connection_helper.rb +++ b/test/support/connection_helper.rb @@ -12,7 +12,7 @@ def mock_connect_to_orientdb(version, socket = nil) begin TCPSocket.stubs(:open).returns(mock_socket) - mock_socket.stubs(:read).returns([version].pack('s>')) + mock_socket.stubs(:read).returns(BinData::Int16be.new(version).to_binary_s) mock_socket.stubs(:close) connection = connect_to_orientdb({}) diff --git a/test/support/protocol_helper.rb b/test/support/protocol_helper.rb index 9ff7492..8ee1c2a 100644 --- a/test/support/protocol_helper.rb +++ b/test/support/protocol_helper.rb @@ -1,22 +1,24 @@ +require 'bindata' + module ProtocolHelper def pack_byte(value) if value.is_a?(String) value = value.length > 0 ? value[0].ord : 0 end - [ value ].pack('C') + BinData::Int8.new(value).to_binary_s end def pack_integer(value) - [ value ].pack('l>') + BinData::Int32be.new(value).to_binary_s end def pack_long(value) - [ value ].pack('q>') + BinData::Int64be.new(value).to_binary_s end def pack_short(value) - [ value ].pack('s>') + BinData::Int16be.new(value).to_binary_s end def pack_string(value) diff --git a/test/unit/protocols/protocol7_test.rb b/test/unit/protocols/protocol7_test.rb index b154470..4b0ea32 100644 --- a/test/unit/protocols/protocol7_test.rb +++ b/test/unit/protocols/protocol7_test.rb @@ -46,6 +46,9 @@ def setup :type => 'LOGICAL' } ] @socket = mock() + @socket.stubs(:pos) + @socket.stubs(:write) + @socket.stubs(:read).with(0).returns('') end def socket_receives(request) @@ -53,18 +56,10 @@ def socket_receives(request) end def test_connect - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::CONNECT - m.add :integer, @protocol::NEW_SESSION - m.add :string, @driver_name - m.add :string, @driver_version - m.add :short, @protocol_version - m.add :string, nil #client-id - m.add :string, @user - m.add :string, @password - }.pack - - socket_receives(request) + inputs = sequence('inputs') + + @socket.expects(:write).once.with(pack_string(@user)).in_sequence(inputs) + @socket.expects(:write).once.with(pack_string(@password)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -87,13 +82,10 @@ def test_count cluster_name = "vertexes" record_count = 1564 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::COUNT - m.add :integer, @session - m.add :string, cluster_name - }.pack + inputs = sequence('inputs') - socket_receives(request) + @socket.expects(:write).once.with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).once.with(pack_string(cluster_name)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -111,21 +103,14 @@ def test_count def test_command command_string = 'SELECT FROM OUser' - command = OrientDbClient::NetworkMessage.new { |m| - m.add :string, 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery' - m.add :string, command_string - m.add :integer, -1 - m.add :integer, 0 - }.pack - - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::COMMAND - m.add :integer, @session - m.add :byte, 's' - m.add :string, command - }.pack + command = @protocol::QueryMessage.new :query_class_name => 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery', + :text => command_string - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::COMMAND)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte('s'.ord)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(command.to_binary_s)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -151,14 +136,11 @@ def test_datacluster_add_logical new_cluster_number = 20 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DATACLUSTER_ADD - m.add :integer, @session - m.add :string, type.to_s.upcase - m.add :integer, container - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DATACLUSTER_ADD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string('LOGICAL')).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(container)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -182,14 +164,11 @@ def test_datacluster_add_memory new_cluster_number = 6 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DATACLUSTER_ADD - m.add :integer, @session - m.add :string, type.to_s.upcase - m.add :string, name - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DATACLUSTER_ADD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string('MEMORY')).in_sequence(inputs) + @socket.expects(:write).with(pack_string(name)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -215,16 +194,13 @@ def test_datacluster_add_physical new_cluster_number = 10 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DATACLUSTER_ADD - m.add :integer, @session - m.add :string, type - m.add :string, name - m.add :string, file_name - m.add :integer, size - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DATACLUSTER_ADD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string('PHYSICAL')).in_sequence(inputs) + @socket.expects(:write).with(pack_string(name)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(file_name)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(size)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -249,13 +225,10 @@ def test_datacluster_datarange range_begin = 0 range_end = 1000 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DATACLUSTER_DATARANGE - m.add :integer, @session - m.add :short, cluster_id - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DATACLUSTER_DATARANGE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -276,13 +249,10 @@ def test_datacluster_datarange def test_datacluster_remove id = 10 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DATACLUSTER_REMOVE - m.add :integer, @session - m.add :short, id - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DATACLUSTER_REMOVE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(id)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -299,12 +269,10 @@ def test_datacluster_remove end def test_db_close - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_CLOSE - m.add :integer, @session - }.pack + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_CLOSE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) - socket_receives(request) @socket.expects(:closed?).returns(true) result = @protocol.db_close(@socket, @session) @@ -315,12 +283,9 @@ def test_db_close def test_db_countrecords count = 26345 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_COUNTRECORDS - m.add :integer, @session - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_COUNTRECORDS)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -339,14 +304,11 @@ def test_db_countrecords def test_db_create storage_type = 'local' - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_CREATE - m.add :integer, @session - m.add :string, @database - m.add :string, storage_type - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_CREATE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(storage_type)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -361,13 +323,10 @@ def test_db_create end def test_db_delete - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_DELETE - m.add :integer, @session - m.add :string, @database - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_DELETE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -382,13 +341,10 @@ def test_db_delete end def test_db_exist - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_EXIST - m.add :integer, @session - m.add :string, @database - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_EXIST)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, @@ -405,19 +361,15 @@ def test_db_exist end def test_db_open - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_OPEN - m.add :integer, @protocol::NEW_SESSION - m.add :string, @driver_name - m.add :string, @driver_version - m.add :short, @protocol_version - m.add :string, nil #client-id - m.add :string, @database - m.add :string, @user - m.add :string, @password - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_OPEN)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@protocol::NEW_SESSION)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@driver_name)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@driver_version)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(@protocol_version)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@user)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@password)).in_sequence(inputs) # recv chain chain = [ @@ -471,16 +423,13 @@ def test_record_create_document_synchronous } } - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::RECORD_CREATE - m.add :integer, @session - m.add :short, cluster_id - m.add :string, @protocol.serializer.serialize(record) - m.add :byte, 'd'.ord - m.add :byte, @protocol::SyncModes::SYNC - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::RECORD_CREATE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@protocol.serializer.serialize(record))).in_sequence(inputs) + @socket.expects(:write).with(pack_byte('d'.ord)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte(@protocol::SyncModes::SYNC)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -501,16 +450,13 @@ def test_record_delete_synchronous cluster_position = 1726 version = 0 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::RECORD_DELETE - m.add :integer, @session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :integer, version - m.add :byte, @protocol::SyncModes::SYNC - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::RECORD_DELETE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) + @socket.expects(:write).with(pack_long(cluster_position)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(version)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte(@protocol::SyncModes::SYNC)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -529,15 +475,11 @@ def test_record_load cluster_id = 3 cluster_position = 6 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::RECORD_LOAD - m.add :integer, @session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :string, "" - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::RECORD_LOAD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) + @socket.expects(:write).with(pack_long(cluster_position)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -566,18 +508,15 @@ def test_record_update_document_synchronous } } - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::RECORD_UPDATE - m.add :integer, @session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :string, @protocol.serializer.serialize(record) - m.add :integer, record_version_policy - m.add :byte, 'd'.ord - m.add :byte, @protocol::SyncModes::SYNC - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::RECORD_UPDATE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) + @socket.expects(:write).with(pack_long(cluster_position)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@protocol.serializer.serialize(record))).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(record_version_policy)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte('d'.ord)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte(@protocol::SyncModes::SYNC)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -593,12 +532,9 @@ def test_record_update_document_synchronous end def test_db_reload - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_RELOAD - m.add :integer, @session - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_RELOAD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) # recv chain chain = [ @@ -636,12 +572,9 @@ def test_db_reload def test_db_size size = 1563467 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_SIZE - m.add :integer, @session - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_SIZE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) chain = [ { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, diff --git a/test/unit/protocols/protocol9_test.rb b/test/unit/protocols/protocol9_test.rb index 4ffbcd2..ed04769 100644 --- a/test/unit/protocols/protocol9_test.rb +++ b/test/unit/protocols/protocol9_test.rb @@ -46,6 +46,9 @@ def setup :type => 'LOGICAL' } ] @socket = mock() + @socket.stubs(:pos) + @socket.stubs(:write) + @socket.stubs(:read).with(0).returns('') end def socket_receives(request) @@ -55,21 +58,14 @@ def socket_receives(request) def test_command command_string = 'SELECT FROM OUser' - command = OrientDbClient::NetworkMessage.new { |m| - m.add :string, 'q' - m.add :string, command_string - m.add :integer, -1 - m.add :integer, 0 - }.pack + command = @protocol::QueryMessage.new :query_class_name => 'q', + :text => command_string - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::COMMAND - m.add :integer, @session - m.add :byte, 's' - m.add :string, command - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::COMMAND)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte('s'.ord)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(command.to_binary_s)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -93,15 +89,12 @@ def test_db_create storage_type = 'local' database_type = 'document' - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::DB_CREATE - m.add :integer, @session - m.add :string, @database - m.add :string, database_type - m.add :string, storage_type - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_CREATE)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(database_type)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(storage_type)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK), @@ -118,20 +111,70 @@ def test_db_create assert_equal @session, result[:session] end + def test_db_open + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::DB_OPEN)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@protocol::NEW_SESSION)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@driver_name)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@driver_version)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(@protocol_version)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@database)).in_sequence(inputs) + @socket.expects(:write).with(pack_string('document')).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@user)).in_sequence(inputs) + @socket.expects(:write).with(pack_string(@password)).in_sequence(inputs) + + # recv chain + chain = [ + { :param => Sizes::BYTE, :return => pack_byte(@protocol::Statuses::OK) }, + { :param => Sizes::INTEGER, :return => pack_integer(@protocol::NEW_SESSION) }, + { :param => Sizes::INTEGER, :return => pack_integer(@session) }, + { :param => Sizes::SHORT, :return => pack_short(@clusters.length) } + ] + + @clusters.each do |cluster| + chain.concat [ + { :param => Sizes::INTEGER, :return => pack_integer(cluster[:name].length) }, + { :param => cluster[:name].length, :return => pack_string(cluster[:name]) }, + { :param => Sizes::SHORT, :return => pack_short(cluster[:id]) }, + { :param => Sizes::INTEGER, :return => pack_integer(cluster[:type].length) }, + { :param => cluster[:type].length, :return => pack_string(cluster[:type]) } + ] + end + + chain << { :param => Sizes::INTEGER, :return => pack_integer(0) } + + chain.map! &SOCKET_RECV_EXPECTATION + # End recv chain + + expect_sequence @socket, chain, 'response' + + result = @protocol.db_open(@socket, @database, { + :user => @user, + :password => @password + }) + + assert_equal @protocol::NEW_SESSION, result[:session] + assert_equal @session, result[:message_content][:session] + assert_equal @clusters.length, result[:message_content][:clusters].length + + @clusters.each_with_index do |c, i| + assert_equal @clusters[i][:id], result[:message_content][:clusters][i][:id] + assert_equal @clusters[i][:name], result[:message_content][:clusters][i][:name] + assert_equal @clusters[i][:type], result[:message_content][:clusters][i][:type] + end + end + def test_record_load cluster_id = 3 cluster_position = 6 - request = OrientDbClient::NetworkMessage.new { |m| - m.add :byte, @protocol::Operations::RECORD_LOAD - m.add :integer, @session - m.add :short, cluster_id - m.add :long, cluster_position - m.add :string, "" - m.add :byte, 0 - }.pack - - socket_receives(request) + inputs = sequence('inputs') + @socket.expects(:write).with(pack_byte(@protocol::Operations::RECORD_LOAD)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(@session)).in_sequence(inputs) + @socket.expects(:write).with(pack_short(cluster_id)).in_sequence(inputs) + @socket.expects(:write).with(pack_long(cluster_position)).in_sequence(inputs) + @socket.expects(:write).with(pack_integer(0)).in_sequence(inputs) + @socket.expects(:write).with(pack_byte(0)).in_sequence(inputs) chain = [ pack_byte(@protocol::Statuses::OK),