Kouhei Sutou
null+****@clear*****
Fri Dec 9 16:27:28 JST 2016
Kouhei Sutou 2016-12-09 16:27:28 +0900 (Fri, 09 Dec 2016) New Revision: 56a06ab966e106cff89ecfa344841edf4ef0edb1 https://github.com/ranguba/groonga-client/commit/56a06ab966e106cff89ecfa344841edf4ef0edb1 Message: Import request interface from groonga-client-rails Added files: lib/groonga/client/request.rb lib/groonga/client/request/base.rb lib/groonga/client/request/select.rb test/request/select/test-filter-parameter.rb test/request/select/test-match-columns-parameter.rb test/request/select/test-output-columns-parameter.rb test/request/select/test-sort-keys-columns-parameter.rb test/request/test-select.rb Modified files: lib/groonga/client.rb lib/groonga/client/response/select.rb test/run-test.rb Modified: lib/groonga/client.rb (+1 -1) =================================================================== --- lib/groonga/client.rb 2016-12-09 16:08:24 +0900 (7e19fe5) +++ lib/groonga/client.rb 2016-12-09 16:27:28 +0900 (46a33e5) @@ -23,7 +23,7 @@ require "groonga/client/command" require "groonga/client/empty-request" require "groonga/client/protocol/gqtp" require "groonga/client/protocol/http" -require "groonga/client/script-syntax" +require "groonga/client/request" module Groonga class Client Added: lib/groonga/client/request.rb (+19 -0) 100644 =================================================================== --- /dev/null +++ lib/groonga/client/request.rb 2016-12-09 16:27:28 +0900 (ca99c9f) @@ -0,0 +1,19 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +require "groonga/client/script-syntax" + +require "groonga/client/request/select" Added: lib/groonga/client/request/base.rb (+95 -0) 100644 =================================================================== --- /dev/null +++ lib/groonga/client/request/base.rb 2016-12-09 16:27:28 +0900 (4bf8688) @@ -0,0 +1,95 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +module Groonga + class Client + module Request + class Base + def initialize(command_name, parameters=nil) + @command_name = command_name + @parameters = parameters + end + + def response + @reponse ||= create_response + end + + def parameter(name, value) + add_parameter(OverwriteMerger, + RequestParameter.new(name, value)) + end + + def to_parameters + if****@param*****? + {} + else + @parameters.to_parameters + end + end + + private + def add_parameter(merger_class, parameter) + merger = merger_class.new(@parameters, parameter) + create_request(merger) + end + + def create_request(parameters) + self.class.new(@command_name, parameters) + end + + def create_response + open_client do |client| + response = client.execute(@command_name, to_parameters) + raise ErrorResponse.new(response) unless response.success? + response + end + end + + def open_client + Client.open do |client| + yield(client) + end + end + end + + class RequestParameter + def initialize(name, value) + @name = name + @value = value + end + + def to_parameters + { + @name => @value, + } + end + end + + class ParameterMerger + def initialize(parameters1, parameters2) + @parameters1 = parameters1 + @parameters2 = parameters2 + end + end + + class OverwriteMerger < ParameterMerger + def to_parameters + @parameters1.to_parameters.merge(@parameters2.to_parameters) + end + end + end + end +end Added: lib/groonga/client/request/select.rb (+289 -0) 100644 =================================================================== --- /dev/null +++ lib/groonga/client/request/select.rb 2016-12-09 16:27:28 +0900 (e0404e9) @@ -0,0 +1,289 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +require "groonga/client/request/base" + +module Groonga + class Client + module Request + class Select < Base + def initialize(table_or_parameters) + if table_or_parameters.respond_to?(:to_parameters) + parameters = table_or_parameters + else + table_name = table_or_parameters + parameters = RequestParameter.new(:table, table_name) + end + super("select", parameters) + end + + def match_columns(value) + add_parameter(OverwriteMerger, + MatchColumnsParameter.new(value)) + end + + def query(value) + add_parameter(QueryMerger, + RequestParameter.new(:query, value)) + end + + def filter(expression, values=nil) + add_parameter(FilterMerger, + FilterParameter.new(expression, values)) + end + + def output_columns(value) + add_parameter(OverwriteMerger, + OutputColumnsParameter.new(value)) + end + + def sort_keys(value) + add_parameter(OverwriteMerger, + SortKeysParameter.new(value)) + end + alias_method :sortby, :sort_keys + alias_method :sort, :sort_keys + + def offset(value) + parameter(:offset, value) + end + + def limit(value) + parameter(:limit, value) + end + + def paginate(page, per_page: 10) + page ||= 1 + page = page.to_i + if page <= 0 + offset = 0 + else + offset = per_page * (page - 1) + end + offset(offset).limit(per_page) + end + + private + def create_request(parameters) + self.class.new(parameters) + end + + def create_response + response = super + if paginated? and defined?(Kaminari) + response.extend(Kaminari::ConfigurationMethods::ClassMethods) + response.extend(Kaminari::PageScopeMethods) + end + response + end + + def paginated? + parameters = to_parameters + parameters.key?(:offset) and parameters.key?(:limit) + end + + # @private + class QueryMerger < ParameterMerger + def to_parameters + params1 =****@param*****_parameters + params2 =****@param*****_parameters + params = params1.merge(params2) + query1 = params1[:query] + query2 = params2[:query] + if query1.present? and query2.present? + params[:query] = "(#{query1}) (#{query2})" + else + params[:query] = (query1 || query2) + end + params + end + end + + # @private + class FilterMerger < ParameterMerger + def to_parameters + params1 =****@param*****_parameters + params2 =****@param*****_parameters + params = params1.merge(params2) + filter1 = params1[:filter] + filter2 = params2[:filter] + if filter1.present? and filter2.present? + params[:filter] = "(#{filter1}) && (#{filter2})" + else + params[:filter] = (filter1 || filter2) + end + params + end + end + + # @private + class MatchColumnsParameter + def initialize(match_columns) + @match_columns = match_columns + end + + def to_parameters + case @match_columns + when ::Array + return {} if @match_columns.empty? + match_columns = @match_columns.join(", ") + when Symbol + match_columns = @match_columns.to_s + when String + return {} if /\A\s*\z/ === @match_columns + match_columns = @match_columns + when NilClass + return {} + else + match_columns = @match_columns + end + { + match_columns: match_columns, + } + end + end + + # @private + class FilterParameter + def initialize(expression, values) + @expression = expression + @values = values + end + + def to_parameters + case @expression + when String + return {} if /\A\s*\z/ === @expression + expression = @expression + when NilClass + return {} + else + expression = @expression + end + + if****@value*****_a?(::Hash) and not****@value*****? + escaped_values = {} + @values.each do |key, value| + escaped_values[key] = escape_filter_value(value) + end + expression = expression % escaped_values + end + + { + filter: expression, + } + end + + private + def escape_filter_value(value) + case value + when Numeric + value + when TrueClass, FalseClass + value + when NilClass + "null" + when String + ScriptSyntax.format_string(value) + when Symbol + ScriptSyntax.format_string(value.to_s) + when ::Array + escaped_value = "[" + value.each_with_index do |element, i| + escaped_value << ", " if i > 0 + escaped_value << escape_filter_value(element) + end + escaped_value << "]" + escaped_value + when ::Hash + escaped_value = "{" + value.each_with_index do |(k, v), i| + escaped_value << ", " if i > 0 + escaped_value << escape_filter_value(k.to_s) + escaped_value << ": " + escaped_value << escape_filter_value(v) + end + escaped_value << "}" + escaped_value + else + value + end + end + end + + # @private + class OutputColumnsParameter + def initialize(output_columns) + @output_columns = output_columns + end + + def to_parameters + case @output_columns + when ::Array + return {} if @output_columns.empty? + output_columns = @output_columns.join(", ") + when Symbol + output_columns = @output_columns.to_s + when String + return {} if /\A\s*\z/ === @output_columns + output_columns = @output_columns + when NilClass + return {} + else + output_columns = @output_columns + end + + parameters = { + output_columns: output_columns, + } + if output_columns.include?("(") + parameters[:command_version] = "2" + end + parameters + end + end + + # @private + class SortKeysParameter + def initialize(keys) + @keys = keys + end + + def to_parameters + case @keys + when ::Array + return {} if****@keys*****? + keys =****@keys*****(&:to_s).join(", ") + when Symbol + keys =****@keys*****_s + when String + return {} if /\A\s*\z/ === @keys + keys = @keys + when NilClass + return {} + else + keys = @keys + end + { + sort_keys: keys, + sortby: keys, # For backward compatibility + } + end + end + end + end + end +end Modified: lib/groonga/client/response/select.rb (+17 -1) =================================================================== --- lib/groonga/client/response/select.rb 2016-12-09 16:08:24 +0900 (b7c0af8) +++ lib/groonga/client/response/select.rb 2016-12-09 16:27:28 +0900 (54a2fde) @@ -26,6 +26,8 @@ module Groonga # @return [Integer] The number of records that match againt # a search condition. attr_accessor :n_hits + # For Kaminari + alias_method :total_count, :n_hits attr_accessor :records # @return [::Array<Groonga::Client::Response::Select::Drilldown>, @@ -42,6 +44,16 @@ module Groonga parse_body(body) end + # For Kaminari + def limit_value + (@command[:limit] || 10).to_i + end + + # For Kaminari + def offset_value + (@command[:offset] || 0).to_i + end + private def parse_body(body) if body.is_a?(::Array) @@ -74,7 +86,7 @@ module Groonga end (raw_records || []).collect do |raw_record| - record = {} + record = Record.new columns.each_with_index do |(name, type), i| record[name] = convert_value(raw_record[i], type) end @@ -139,6 +151,10 @@ module Groonga drilldowns end + class Record < ::Hash + include Hashie::Extensions::MethodAccess + end + class Drilldown < Struct.new(:key, :n_hits, :records) # @deprecated since 0.2.6. Use {#records} instead. alias_method :items, :records Added: test/request/select/test-filter-parameter.rb (+97 -0) 100644 =================================================================== --- /dev/null +++ test/request/select/test-filter-parameter.rb 2016-12-09 16:27:28 +0900 (7e76631) @@ -0,0 +1,97 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class TestRequestSelectFilterParmater < Test::Unit::TestCase + def filter_parameter(expression, values=nil) + Groonga::Client::Request::Select::FilterParameter.new(expression, values) + end + + def to_parameters(expression, values=nil) + filter_parameter(expression, values).to_parameters + end + + sub_test_case("expression") do + def test_nil + assert_equal({}, + to_parameters(nil)) + end + + def test_string + assert_equal({ + :filter => "age <= 20", + }, + to_parameters("age <= 20")) + end + + def test_empty_string + assert_equal({}, + to_parameters("")) + end + end + + sub_test_case("values") do + def test_string + filter = <<-'FILTER'.strip +title == "[\"He\\ llo\"]" + FILTER + assert_equal({ + :filter => filter, + }, + to_parameters("title == %{value}", + :value => "[\"He\\ llo\"]")) + end + + def test_symbol + assert_equal({ + :filter => "title == \"Hello\"", + }, + to_parameters("title == %{value}", + :value => :Hello)) + end + + def test_number + assert_equal({ + :filter => "age <= 29", + }, + to_parameters("age <= %{value}", + :value => 29)) + end + + def test_true + assert_equal({ + :filter => "published == true", + }, + to_parameters("published == %{value}", + :value => true)) + end + + def test_false + assert_equal({ + :filter => "published == false", + }, + to_parameters("published == %{value}", + :value => false)) + end + + def test_nil + assert_equal({ + :filter => "function(null)", + }, + to_parameters("function(%{value})", + :value => nil)) + end + end +end Added: test/request/select/test-match-columns-parameter.rb (+57 -0) 100644 =================================================================== --- /dev/null +++ test/request/select/test-match-columns-parameter.rb 2016-12-09 16:27:28 +0900 (6aa7c3e) @@ -0,0 +1,57 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class TestRequestSelectMatchColumnsParmater < Test::Unit::TestCase + def match_columns_parameter(match_columns) + Groonga::Client::Request::Select::MatchColumnsParameter.new(match_columns) + end + + def test_nil + assert_equal({}, + match_columns_parameter(nil).to_parameters) + end + + def test_string + assert_equal({ + :match_columns => "title", + }, + match_columns_parameter("title").to_parameters) + end + + def test_empty_string + assert_equal({}, + match_columns_parameter("").to_parameters) + end + + def test_symbol + assert_equal({ + :match_columns => "title", + }, + match_columns_parameter(:title).to_parameters) + end + + def test_array + assert_equal({ + :match_columns => "title, body", + }, + match_columns_parameter(["title", "body"]).to_parameters) + end + + def test_empty_array + assert_equal({}, + match_columns_parameter([]).to_parameters) + end +end Added: test/request/select/test-output-columns-parameter.rb (+66 -0) 100644 =================================================================== --- /dev/null +++ test/request/select/test-output-columns-parameter.rb 2016-12-09 16:27:28 +0900 (cdf5db8) @@ -0,0 +1,66 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class TestRequestSelectOutputColumnsParmater < Test::Unit::TestCase + def output_columns_parameter(output_columns) + Groonga::Client::Request::Select::OutputColumnsParameter.new(output_columns) + end + + def test_nil + assert_equal({}, + output_columns_parameter(nil).to_parameters) + end + + def test_string + assert_equal({ + :output_columns => "title", + }, + output_columns_parameter("title").to_parameters) + end + + def test_empty_string + assert_equal({}, + output_columns_parameter("").to_parameters) + end + + def test_symbol + assert_equal({ + :output_columns => "title", + }, + output_columns_parameter(:title).to_parameters) + end + + def test_array + assert_equal({ + :output_columns => "title, body", + }, + output_columns_parameter(["title", "body"]).to_parameters) + end + + def test_empty_array + assert_equal({}, + output_columns_parameter([]).to_parameters) + end + + def test_function + parameter = output_columns_parameter(["title", "snippet_html(body)"]) + assert_equal({ + :output_columns => "title, snippet_html(body)", + :command_version => "2", + }, + parameter.to_parameters) + end +end Added: test/request/select/test-sort-keys-columns-parameter.rb (+64 -0) 100644 =================================================================== --- /dev/null +++ test/request/select/test-sort-keys-columns-parameter.rb 2016-12-09 16:27:28 +0900 (5810e11) @@ -0,0 +1,64 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class TestRequestSelectSortKeysParmater < Test::Unit::TestCase + def sort_keys_parameter(sort_keys) + Groonga::Client::Request::Select::SortKeysParameter.new(sort_keys) + end + + def to_parameters(sort_keys) + sort_keys_parameter(sort_keys).to_parameters + end + + def test_nil + assert_equal({}, + to_parameters(nil)) + end + + def test_string + assert_equal({ + :sort_keys => "-_score, _id", + :sortby => "-_score, _id", + }, + to_parameters("-_score, _id")) + end + + def test_empty_string + assert_equal({}, + to_parameters("")) + end + + def test_symbol + assert_equal({ + :sort_keys => "_score", + :sortby => "_score", + }, + to_parameters(:_score)) + end + + def test_array + assert_equal({ + :sort_keys => "-_score, _id", + :sortby => "-_score, _id", + }, + to_parameters(["-_score", :_id])) + end + + def test_empty_array + assert_equal({}, + to_parameters([])) + end +end Added: test/request/test-select.rb (+494 -0) 100644 =================================================================== --- /dev/null +++ test/request/test-select.rb 2016-12-09 16:27:28 +0900 (1448dd7) @@ -0,0 +1,494 @@ +# Copyright (C) 2016 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class TestSelectResponse < Test::Unit::TestCase + module ClientFixture + class << self + def included(base) + super + base.class_eval do + setup :setup_client + teardown :teardown_client + end + end + end + + def setup_client + @client = nil + end + + def teardown_client + @client.close if @client + end + end + + module Utils + def client + @client ||= open_client + end + + def open_options + url = "#{@protocol}://" + if @user and @password + url << URI.encode_www_form_component(@user) + url << ":" + url << URI.encode_www_form_component(@password) + url << "@" + end + url << "#{@address}:#{@port}" + {:url => url} + end + + def open_client(&block) + Groonga::Client.open(open_options, &block) + end + + def stub_response(body, output_type=:json) + @response_body = body + @response_output_type = output_type + end + end + + module Assertions + NORMALIZED_START_TIME = Time.parse("2013-05-23T16:43:39+09:00").to_i + NORMALIZED_ELAPSED_TIME = 29 + def normalize_header(header) + normalized_header = header.dup + start_time = header[1] + if start_time.is_a?(Numeric) + normalized_header[1] = NORMALIZED_START_TIME + end + elapsed_time = header[2] + if elapsed_time.is_a?(Numeric) + normalized_header[2] = NORMALIZED_ELAPSED_TIME + end + normalized_header + end + + def assert_header(response) + normalized_header = normalize_header(response.header) + assert_equal([0, NORMALIZED_START_TIME, NORMALIZED_ELAPSED_TIME], + normalized_header) + end + + def assert_response(expected_body, response) + if @response_output_type == :none + expected_header = nil + actual_header = response.header + else + expected_header = [ + 0, + NORMALIZED_START_TIME, + NORMALIZED_ELAPSED_TIME, + ] + actual_header = normalize_header(response.header) + end + actual_body = response.body + actual_body = yield(actual_body) if block_given? + assert_equal({ + :header => expected_header, + :body => expected_body, + }, + { + :header => actual_header, + :body => actual_body, + }) + end + end + + module OutputTypeTests + def test_dump + dumped_commands = "table_create TEST_TABLE TABLE_NO_KEY" + stub_response(dumped_commands, :none) + response = client.dump + assert_response(dumped_commands, response) + end + + def test_xml + stub_response(<<-XML, :xml) +<TABLE_LIST> +<HEADER> +<PROPERTY> +<TEXT>id</TEXT> +<TEXT>UInt32</TEXT></PROPERTY> +<PROPERTY> +<TEXT>name</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>path</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>flags</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>domain</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>range</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>default_tokenizer</TEXT> +<TEXT>ShortText</TEXT></PROPERTY> +<PROPERTY> +<TEXT>normalizer</TEXT> +<TEXT>ShortText</TEXT></PROPERTY></HEADER> +<TABLE> +<INT>256</INT> +<TEXT>Users</TEXT> +<TEXT>/tmp/db/db.0000100</TEXT> +<TEXT>TABLE_HASH_KEY|PERSISTENT</TEXT> +<NULL/> +<NULL/> +<NULL/> +<NULL/></TABLE></TABLE_LIST> + XML + response = client.table_list(:output_type => :xml) + expected_body = [ + [ + ["id", "UInt32"], + ["name", "ShortText"], + ["path", "ShortText"], + ["flags", "ShortText"], + ["domain", "ShortText"], + ["range", "ShortText"], + ["default_tokenizer", "ShortText"], + ["normalizer", "ShortText"], + ], + [ + 256, + "Users", + "/tmp/db/db.0000100", + "TABLE_HASH_KEY|PERSISTENT", + nil, + nil, + nil, + nil, + ], + ] + assert_response(expected_body, response) + end + end + + module ColumnsTests + def test_not_exist + stub_response('{"key":"value"}') + response = client.status + assert_response({"key" => "value"}, response) + end + + def disabled_test_exist + stub_response(<<-JSON) +[[["name","ShortText"], +["age","UInt32"]], +["Alice",32], +["Bob",21]] +JSON + expected_table_infos = [ + {:name => "Alice", :age => 32}, + {:name => "Bob", :age => 21} + ] + response = client.table_list + assert_response(expected_table_infos, response) do |actual_body| + actual_body.collect do |value| + value.table_info + end + end + end + end + + module ParametersTests + def test_integer + stub_response("100") + response = client.cache_limit(:max => 4) + assert_response(100, response) + end + end + + module OpenTests + def test_return_value + stub_response("['not-used']") + response = open_client do |client| + "response" + end + assert_equal("response", response) + end + + def test_open_components + stub_response("[29]") + options = { + :host => @address, + :port => @port, + :protocol => @protocol, + } + response = Groonga::Client.open(options) do |client| + client.status + end + assert_equal([29], response.body) + end + end + + module LoadTests + def test_load_json + values = [ + {"content" => "1st content"}, + {"content" => "2nd content"}, + {"content" => "3rd content"}, + ] + stub_response("[#{values.size}]") + response = client.load(:table => "Memos", + :values => JSON.generate(values)) + assert_equal([values.size], response.body) + assert_equal([values], + @actual_commands.collect(&:values)) + end + + def test_load_array + values = [ + {"content" => "1st content"}, + {"content" => "2nd content"}, + {"content" => "3rd content"}, + ] + stub_response("[#{values.size}]") + response = client.load(:table => "Memos", + :values => values) + assert_equal([values.size], response.body) + assert_equal([values], + @actual_commands.collect(&:values)) + end + end + + module DefaultOptionsTests + def test_default_options + change_default_options(open_options) do + expected_response = {"key" => "value"} + stub_response(expected_response.to_json) + response = Groonga::Client.open do |client| + client.status + end + assert_equal(expected_response, response.body) + end + end + + def change_default_options(options) + default_options = Groonga::Client.default_options + begin + Groonga::Client.default_options = options + yield + ensure + Groonga::Client.default_options = default_options + end + end + end + + module Tests + include Utils + include Assertions + + include OutputTypeTests + include ColumnsTests + include ParametersTests + include OpenTests + include LoadTests + include DefaultOptionsTests + end + + class TestGQTP < self + include Tests + include ClientFixture + + def setup + @address = "127.0.0.1" + @server = TCPServer.new(@address, 0) + @port =****@serve*****[1] + @protocol = :gqtp + + @user = nil + @password = nil + @actual_commands = [] + @response_body = nil + @thread = Thread.new do + client =****@serve***** + @server.close + + loop do + raw_header = client.read(GQTP::Header.size) + break if raw_header.nil? + + header = GQTP::Header.parse(raw_header) + body = client.read(header.size) + @actual_commands << Groonga::Command::Parser.parse(body) + + response_header = GQTP::Header.new + response_header.size = @response_body.bytesize + + client.write(response_header.pack) + client.write(@response_body) + end + + client.close + end + end + + def teardown + @thread.kill + end + end + + class TestHTTP < self + include Tests + include ClientFixture + + def setup + @address = "127.0.0.1" + @server = TCPServer.new(@address, 0) + @port =****@serve*****[1] + @protocol = :http + + setup_authentication + @request_headers = {} + @request_path = nil + @actual_commands = [] + @response_body = nil + @thread = Thread.new do + client =****@serve***** + first_line = client.gets + if /\A([\w]+) ([^ ]+) HTTP/ =~ first_line + # http_method = $1 + @request_path = $2 + headers = {} + client.each_line do |line| + case line + when "\r\n" + break + else + name, value = line.strip.split(/: */, 2) + headers[name.downcase] = value + end + end + @request_headers = headers + content_length = headers["content-length"] + if content_length + body = client.read(Integer(content_length)) + else + body = nil + end + command = Groonga::Command::Parser.parse(@request_path) + command[:values] = body if body + @actual_commands << command + end + @server.close + + status = 0 + start = Time.now.to_f + elapsed = rand + case @response_output_type + when :json + header = "[#{status},#{start},#{elapsed}]" + body = "[#{header},#{@response_body}]" + when :xml + body = <<-XML +<RESULT CODE="#{status}" UP="#{start}" ELAPSED="#{elapsed}"> +#{@response_body} +</RESULT> + XML + else + body = @response_body + end + header = <<-EOH +HTTP/1.1 200 OK +Connection: close +Content-Type: application/json +Content-Length: #{body.bytesize} + +EOH + client.write(header) + client.write(body) + client.close + end + end + + def setup_authentication + @user = nil + @password = nil + end + + class TestLoad < self + def test_path + stub_response("[]") + client.load(:table => "Memos", :values => []) + assert_equal("/d/load?table=Memos", @request_path) + end + end + + class TestBasicAuthentication < self + def setup_authentication + @user = "Aladdin" + @password = "open sesame" + end + + def test_request_header + stub_response("[]") + client.status + assert_equal("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + @request_headers["authorization"]) + end + + def test_open_components + stub_response("[]") + options = { + :host => @address, + :port => @port, + :protocol => @protocol, + :user => @user, + :password => @password, + } + Groonga::Client.open(options) do |client| + client.status + end + assert_equal("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + @request_headers["authorization"]) + end + end + + class TestPath < self + def component_based_open_options + { + :protocol => @protocol, + :host => @address, + :port => @port, + } + end + + def test_with_trailing_slash + stub_response("[]") + options = component_based_open_options.merge(:path => "/sub_path/") + Groonga::Client.open(options) do |client| + client.status + end + assert_equal("/sub_path/d/status", @request_path) + end + + def test_without_trailing_slash + stub_response("[]") + options = component_based_open_options.merge(:path => "/sub_path") + Groonga::Client.open(options) do |client| + client.status + end + assert_equal("/sub_path/d/status", @request_path) + end + end + end +end Modified: test/run-test.rb (+1 -0) =================================================================== --- test/run-test.rb 2016-12-09 16:08:24 +0900 (7dbc9fd) +++ test/run-test.rb 2016-12-09 16:27:28 +0900 (4c6dbf3) @@ -41,6 +41,7 @@ test_dir = base_dir + "test" $LOAD_PATH.unshift(lib_dir.to_s) require "test-unit" +require "groonga/client" Thread.abort_on_exception = true -------------- next part -------------- HTML����������������������������... Descargar