From d0d6ce7a289a6bc51f66fcde2d5807830aaa55e5 Mon Sep 17 00:00:00 2001 From: Georgy Moiseev Date: Tue, 12 Mar 2024 11:26:28 +0300 Subject: [PATCH] test: check decimal filters Module uses cdata string cast for decimal filters. Later they are compared to decimal objects and casted back, so everything already works fine. Part of #373 --- test/entrypoint/srv_select/storage_init.lua | 97 +++++++++ test/helper.lua | 23 ++ test/integration/pairs_readview_test.lua | 7 +- test/integration/pairs_test.lua | 7 +- test/integration/read_scenario.lua | 226 ++++++++++++++++++++ test/integration/select_readview_test.lua | 7 +- test/integration/select_test.lua | 7 +- 7 files changed, 370 insertions(+), 4 deletions(-) diff --git a/test/entrypoint/srv_select/storage_init.lua b/test/entrypoint/srv_select/storage_init.lua index 6e66e9af..72409d16 100644 --- a/test/entrypoint/srv_select/storage_init.lua +++ b/test/entrypoint/srv_select/storage_init.lua @@ -1,4 +1,5 @@ local datetime_supported, _ = pcall(require, 'datetime') +local decimal_supported, _ = pcall(require, 'decimal') local crud_utils = require('crud.common.utils') return function() @@ -229,6 +230,102 @@ return function() if_not_exists = true, }) + if decimal_supported then + local decimal_format = { + {name = 'id', type = 'unsigned'}, + {name = 'bucket_id', type = 'unsigned'}, + {name = 'decimal_field', type = 'decimal'}, + } + + + local decimal_nonindexed_space = box.schema.space.create('decimal_nonindexed', { + if_not_exists = true, + engine = engine, + }) + + decimal_nonindexed_space:format(decimal_format) + + decimal_nonindexed_space:create_index('id_index', { + parts = { 'id' }, + if_not_exists = true, + }) + + decimal_nonindexed_space:create_index('bucket_id', { + parts = { 'bucket_id' }, + unique = false, + if_not_exists = true, + }) + + + local decimal_indexed_space = box.schema.space.create('decimal_indexed', { + if_not_exists = true, + engine = engine, + }) + + decimal_indexed_space:format(decimal_format) + + decimal_indexed_space:create_index('id_index', { + parts = { 'id' }, + if_not_exists = true, + }) + + decimal_indexed_space:create_index('bucket_id', { + parts = { 'bucket_id' }, + unique = false, + if_not_exists = true, + }) + + decimal_indexed_space:create_index('decimal_index', { + parts = { 'decimal_field' }, + unique = false, + if_not_exists = true, + }) + + + local decimal_pk_space = box.schema.space.create('decimal_pk', { + if_not_exists = true, + engine = engine, + }) + + decimal_pk_space:format(decimal_format) + + decimal_pk_space:create_index('decimal_index', { + parts = { 'decimal_field' }, + if_not_exists = true, + }) + + decimal_pk_space:create_index('bucket_id', { + parts = { 'bucket_id' }, + unique = false, + if_not_exists = true, + }) + + + local decimal_multipart_index_space = box.schema.space.create('decimal_multipart_index', { + if_not_exists = true, + engine = engine, + }) + + decimal_multipart_index_space:format(decimal_format) + + decimal_multipart_index_space:create_index('id_index', { + parts = { 'id' }, + if_not_exists = true, + }) + + decimal_multipart_index_space:create_index('bucket_id', { + parts = { 'bucket_id' }, + unique = false, + if_not_exists = true, + }) + + decimal_multipart_index_space:create_index('decimal_index', { + parts = { 'id', 'decimal_field' }, + unique = false, + if_not_exists = true, + }) + end + if datetime_supported then local datetime_format = { {name = 'id', type = 'unsigned'}, diff --git a/test/helper.lua b/test/helper.lua index 67bd9b94..9bbf47e8 100644 --- a/test/helper.lua +++ b/test/helper.lua @@ -958,9 +958,32 @@ function helpers.prepare_ordered_data(g, space, expected_objects, bucket_id, ord t.assert_equals(objects, expected_objects) end +function helpers.skip_decimal_unsupported() + local module_available, _ = pcall(require, 'decimal') + t.skip_if(not module_available, 'decimal is not supported') +end + function helpers.skip_datetime_unsupported() local module_available, _ = pcall(require, 'datetime') t.skip_if(not module_available, 'datetime is not supported') end +function helpers.merge_tables(t1, t2, ...) + if t2 == nil then + return t1 + end + + local res = {} + + for k, v in pairs(t1) do + res[k] = v + end + + for k, v in pairs(t2) do + res[k] = v + end + + return helpers.merge_tables(res, ...) +end + return helpers diff --git a/test/integration/pairs_readview_test.lua b/test/integration/pairs_readview_test.lua index b35581c3..cc1fe856 100644 --- a/test/integration/pairs_readview_test.lua +++ b/test/integration/pairs_readview_test.lua @@ -907,7 +907,12 @@ pgroup.test_gh_418_pairs_with_secondary_noneq_index_condition = function(g) read_scenario.gh_418_read_with_secondary_noneq_index_condition(g, read_impl) end -for case_name_template, case in pairs(read_scenario.gh_373_read_with_datetime_condition_cases) do +local gh_373_types_cases = helpers.merge_tables( + read_scenario.gh_373_read_with_decimal_condition_cases, + read_scenario.gh_373_read_with_datetime_condition_cases +) + +for case_name_template, case in pairs(gh_373_types_cases) do local case_name = 'test_' .. case_name_template:format('pairs') pgroup[case_name] = function(g) diff --git a/test/integration/pairs_test.lua b/test/integration/pairs_test.lua index 6169ca67..097784a0 100644 --- a/test/integration/pairs_test.lua +++ b/test/integration/pairs_test.lua @@ -915,7 +915,12 @@ pgroup.test_gh_418_pairs_with_secondary_noneq_index_condition = function(g) read_scenario.gh_418_read_with_secondary_noneq_index_condition(g, read_impl) end -for case_name_template, case in pairs(read_scenario.gh_373_read_with_datetime_condition_cases) do +local gh_373_types_cases = helpers.merge_tables( + read_scenario.gh_373_read_with_decimal_condition_cases, + read_scenario.gh_373_read_with_datetime_condition_cases +) + +for case_name_template, case in pairs(gh_373_types_cases) do local case_name = 'test_' .. case_name_template:format('pairs') pgroup[case_name] = function(g) diff --git a/test/integration/read_scenario.lua b/test/integration/read_scenario.lua index ea8cf919..18c6a27e 100644 --- a/test/integration/read_scenario.lua +++ b/test/integration/read_scenario.lua @@ -6,6 +6,7 @@ local t = require('luatest') local datetime_supported, datetime = pcall(require, 'datetime') +local decimal_supported, decimal = pcall(require, 'decimal') local helpers = require('test.helper') @@ -86,6 +87,230 @@ local function build_condition_case( end +local decimal_vals = {} + +if decimal_supported then + decimal_vals = { + smallest_negative = decimal.new('-123.1251412'), + bigger_negative = decimal.new('-123.12'), + bigger_positive = decimal.new('31251.6311783'), + } + + assert(decimal_vals.smallest_negative < decimal_vals.bigger_negative) + assert(decimal_vals.bigger_negative < decimal_vals.bigger_positive) +end + + +local decimal_data = { + { + id = 1, + decimal_field = decimal_vals.smallest_negative, + }, + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + { + id = 3, + decimal_field = decimal_vals.bigger_positive, + }, +} + + +local function bigger_negative_condition(operator, operand, is_multipart) + if is_multipart then + return {operator, operand, {2, decimal_vals.bigger_negative}} + else + return {operator, operand, decimal_vals.bigger_negative} + end +end + +local decimal_condition_operator_options = { + single_lt = function(operand, is_multipart) + return { + conditions = {bigger_negative_condition('<', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 1, + decimal_field = decimal_vals.smallest_negative, + }, + }, + } + end, + single_le = function(operand, is_multipart) + return { + conditions = {bigger_negative_condition('<=', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 1, + decimal_field = decimal_vals.smallest_negative, + }, + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + }, + } + end, + single_eq = function(operand, is_multipart) + return { + conditions = {bigger_negative_condition('==', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + }, + } + end, + single_ge = function(operand, is_multipart) + return { + conditions = {bigger_negative_condition('>=', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + { + id = 3, + decimal_field = decimal_vals.bigger_positive, + }, + }, + } + end, + single_gt = function(operand, is_multipart) + return { + conditions = {bigger_negative_condition('>', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 3, + decimal_field = decimal_vals.bigger_positive, + }, + }, + } + end, + second_lt = function(operand, is_multipart) + return { + conditions = {{'>=', 'id', 1}, bigger_negative_condition('<', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 1, + decimal_field = decimal_vals.smallest_negative, + }, + }, + } + end, + second_le = function(operand, is_multipart) + return { + conditions = {{'>=', 'id', 1}, bigger_negative_condition('<=', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 1, + decimal_field = decimal_vals.smallest_negative, + }, + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + }, + } + end, + second_eq = function(operand, is_multipart) + return { + conditions = {{'>=', 'id', 1}, bigger_negative_condition('==', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + }, + } + end, + second_ge = function(operand, is_multipart) + return { + conditions = {{'>=', 'id', 1}, bigger_negative_condition('>=', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 2, + decimal_field = decimal_vals.bigger_negative, + }, + { + id = 3, + decimal_field = decimal_vals.bigger_positive, + }, + }, + } + end, + second_gt = function(operand, is_multipart) + return { + conditions = {{'>=', 'id', 1}, bigger_negative_condition('>', operand, is_multipart)}, + expected_objects_without_bucket_id = { + { + id = 3, + decimal_field = decimal_vals.bigger_positive, + }, + }, + } + end, +} + + +local decimal_condition_space_options = { + nonindexed = { + space_name = 'decimal_nonindexed', + index_kind = nil, + }, + indexed = { + space_name = 'decimal_indexed', + index_kind = 'secondary', + }, + pk = { + space_name = 'decimal_pk', + index_kind = 'primary', + }, + multipart_indexed = { + space_name = 'decimal_multipart_index', + index_kind = 'multipart', + is_multipart = true, + }, +} + + +local gh_373_read_with_decimal_condition_cases = {} + +for space_kind, space_option in pairs(decimal_condition_space_options) do + for operator_kind, operator_options_builder in pairs(decimal_condition_operator_options) do + local field_case_name_template = ('gh_373_%%s_by_decimal_%s_field_%s_condition'):format( + space_kind, operator_kind) + + local field_operator_options = operator_options_builder('decimal_field', false) + + gh_373_read_with_decimal_condition_cases[field_case_name_template] = build_condition_case( + helpers.skip_decimal_unsupported, + space_option.space_name, + decimal_data, + field_operator_options.conditions, + field_operator_options.expected_objects_without_bucket_id + ) + + if space_option.index_kind ~= nil then + local index_case_name_template = ('gh_373_%%s_by_decimal_%s_index_%s_condition'):format( + space_option.index_kind, operator_kind) + + local index_operator_options = operator_options_builder('decimal_index', space_option.is_multipart) + + gh_373_read_with_decimal_condition_cases[index_case_name_template] = build_condition_case( + helpers.skip_decimal_unsupported, + space_option.space_name, + decimal_data, + index_operator_options.conditions, + index_operator_options.expected_objects_without_bucket_id + ) + end + end +end + + local datetime_vals = {} if datetime_supported then @@ -324,5 +549,6 @@ end return { gh_418_read_with_secondary_noneq_index_condition = gh_418_read_with_secondary_noneq_index_condition, + gh_373_read_with_decimal_condition_cases = gh_373_read_with_decimal_condition_cases, gh_373_read_with_datetime_condition_cases = gh_373_read_with_datetime_condition_cases, } diff --git a/test/integration/select_readview_test.lua b/test/integration/select_readview_test.lua index 4cfccdc7..316e5280 100644 --- a/test/integration/select_readview_test.lua +++ b/test/integration/select_readview_test.lua @@ -2506,7 +2506,12 @@ pgroup.test_gh_418_select_with_secondary_noneq_index_condition = function(g) read_scenario.gh_418_read_with_secondary_noneq_index_condition(g, read_impl) end -for case_name_template, case in pairs(read_scenario.gh_373_read_with_datetime_condition_cases) do +local gh_373_types_cases = helpers.merge_tables( + read_scenario.gh_373_read_with_decimal_condition_cases, + read_scenario.gh_373_read_with_datetime_condition_cases +) + +for case_name_template, case in pairs(gh_373_types_cases) do local case_name = 'test_' .. case_name_template:format('select') pgroup[case_name] = function(g) diff --git a/test/integration/select_test.lua b/test/integration/select_test.lua index 4b23f178..0d546704 100644 --- a/test/integration/select_test.lua +++ b/test/integration/select_test.lua @@ -2283,7 +2283,12 @@ pgroup.test_gh_418_select_with_secondary_noneq_index_condition = function(g) read_scenario.gh_418_read_with_secondary_noneq_index_condition(g, read_impl) end -for case_name_template, case in pairs(read_scenario.gh_373_read_with_datetime_condition_cases) do +local gh_373_types_cases = helpers.merge_tables( + read_scenario.gh_373_read_with_decimal_condition_cases, + read_scenario.gh_373_read_with_datetime_condition_cases +) + +for case_name_template, case in pairs(gh_373_types_cases) do local case_name = 'test_' .. case_name_template:format('select') pgroup[case_name] = function(g)