Skip to content

Commit 830f03b

Browse files
committed
sharding: fail fast on invalid bucket_id in data or opts
- Added early validation of bucket_id in tuple/object and in opts inside tuple_set_and_return_bucket_id(). - Error messages now specify where the invalid value was provided: * "Invalid bucket_id in data: expected unsigned, got %s" * "Invalid bucket_id in opts: expected unsigned, got %s" - Extended integration tests for insert/replace/upsert to cover these cases.
1 parent c52a6f5 commit 830f03b

File tree

8 files changed

+111
-48
lines changed

8 files changed

+111
-48
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ sdk: sdk-2 sdk-3
2828
chmod 644 sdk-3/rocks/* && \
2929
tt rocks make_manifest sdk-3/rocks
3030

31-
lint: .rocks
31+
lint:
3232
source sdk-2/env.sh && .rocks/bin/luacheck .
3333

3434
.PHONY: test

crud/common/sharding/init.lua

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,13 @@ function sharding.tuple_get_bucket_id(vshard_router, tuple, space, specified_buc
8282
}
8383
end
8484

85-
function sharding.validate_bucket_id(bucket_id)
85+
function sharding.validate_bucket_id(bucket_id, where)
86+
where = where or 'opts'
87+
8688
if not utils.is_uint(bucket_id) or bucket_id < 1 then
8789
return BucketIDError:new(
88-
"Invalid bucket_id: expected unsigned, got %s",
89-
type(bucket_id)
90+
"Invalid bucket_id in %s: expected unsigned, got %s",
91+
where, type(bucket_id)
9092
)
9193
end
9294
end
@@ -97,7 +99,19 @@ function sharding.tuple_set_and_return_bucket_id(vshard_router, tuple, space, sp
9799
return nil, BucketIDError:new("Failed to get bucket ID fieldno: %s", err)
98100
end
99101

102+
if tuple[bucket_id_fieldno] ~= nil then
103+
err = sharding.validate_bucket_id(tuple[bucket_id_fieldno], 'data')
104+
if err ~= nil then
105+
return nil, err
106+
end
107+
end
108+
100109
if specified_bucket_id ~= nil then
110+
err = sharding.validate_bucket_id(specified_bucket_id)
111+
if err ~= nil then
112+
return nil, err
113+
end
114+
101115
if tuple[bucket_id_fieldno] == nil then
102116
tuple[bucket_id_fieldno] = specified_bucket_id
103117
else
@@ -122,11 +136,6 @@ function sharding.tuple_set_and_return_bucket_id(vshard_router, tuple, space, sp
122136
sharding_data.skip_sharding_hash_check = true
123137
end
124138

125-
err = sharding.validate_bucket_id(sharding_data.bucket_id)
126-
if err ~= nil then
127-
return nil, err
128-
end
129-
130139
return sharding_data
131140
end
132141

test/integration/count_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ pgroup.test_invalid_bucket_id_in_opts = function(g)
925925

926926
for _, bucket_id in ipairs(invalid_values) do
927927
local expected_err = string.format(
928-
"Invalid bucket_id: expected unsigned, got %s",
928+
"Invalid bucket_id in opts: expected unsigned, got %s",
929929
type(bucket_id)
930930
)
931931

test/integration/pairs_readview_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ pgroup.test_invalid_bucket_id_in_readview_pairs = function(g)
957957

958958
for _, opts in ipairs(invalid_opts_list) do
959959
local expected_err = string.format(
960-
"Invalid bucket_id: expected unsigned, got %s",
960+
"Invalid bucket_id in opts: expected unsigned, got %s",
961961
type(opts.bucket_id)
962962
)
963963
local _, err = g.router:eval([[

test/integration/pairs_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ pgroup.test_invalid_bucket_id_pairs = function(g)
964964

965965
for _, opts in ipairs(invalid_opts_list) do
966966
local expected_err = string.format(
967-
"Invalid bucket_id: expected unsigned, got %s",
967+
"Invalid bucket_id in opts: expected unsigned, got %s",
968968
type(opts.bucket_id)
969969
)
970970
t.assert_error_msg_contains(expected_err, function()

test/integration/select_readview_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2575,7 +2575,7 @@ pgroup.test_invalid_bucket_id_in_readview = function(g)
25752575

25762576
for _, opts in ipairs(invalid_opts_list) do
25772577
local expected_err = string.format(
2578-
"Invalid bucket_id: expected unsigned, got %s",
2578+
"Invalid bucket_id in opts: expected unsigned, got %s",
25792579
type(opts.bucket_id)
25802580
)
25812581
local _, err = g.router:eval([[

test/integration/select_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2339,7 +2339,7 @@ pgroup.test_select_invalid_bucket_id = function(g)
23392339
opts.fullscan = true
23402340

23412341
local expected_err = string.format(
2342-
"Invalid bucket_id: expected unsigned, got %s",
2342+
"Invalid bucket_id in opts: expected unsigned, got %s",
23432343
type(opts.bucket_id)
23442344
)
23452345

test/integration/simple_operations_test.lua

Lines changed: 88 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,48 +1743,103 @@ pgroup.test_invalid_bucket_id_operations = function(g)
17431743
helpers.truncate_space_on_cluster(g.cluster, 'customers')
17441744

17451745
local invalid_bucket_id = 'bad-id'
1746-
local expected_err = string.format('Invalid bucket_id: expected unsigned, got %s', type(invalid_bucket_id))
1746+
local ERR_IN_DATA = string.format('Invalid bucket_id in data: expected unsigned, got %s', type(invalid_bucket_id))
1747+
local ERR_IN_OPTS = string.format('Invalid bucket_id in opts: expected unsigned, got %s', type(invalid_bucket_id))
17471748

1748-
local key = 1
1749-
local tuple = {key, invalid_bucket_id, 'Test', 42}
1750-
local tuple_clean = {key, box.NULL, 'Test', 42}
1751-
local object = {id = key + 1000, bucket_id = invalid_bucket_id, name = 'Test', age = 42}
1752-
local object_clean = {id = key + 1001, name = 'Test', age = 42}
1753-
local operations = {{'=', 'name', 'NewName'}}
1749+
local base = 10000
17541750

1755-
local crud_calls = {
1756-
{'crud.insert', {'customers', tuple, {}}},
1757-
{'crud.insert', {'customers', tuple_clean, {bucket_id = invalid_bucket_id}}},
1758-
1759-
{'crud.insert_object', {'customers', object, {}}},
1760-
{'crud.insert_object', {'customers', object_clean, {bucket_id = invalid_bucket_id}}},
1761-
1762-
{'crud.replace', {'customers', tuple, {}}},
1763-
{'crud.replace', {'customers', tuple_clean, {bucket_id = invalid_bucket_id}}},
1764-
1765-
{'crud.replace_object', {'customers', object, {}}},
1766-
{'crud.replace_object', {'customers', object_clean, {bucket_id = invalid_bucket_id}}},
1767-
1768-
{'crud.upsert', {'customers', tuple, operations, {}}},
1769-
{'crud.upsert', {'customers', tuple_clean, operations, {bucket_id = invalid_bucket_id}}},
1751+
local tuple_bad = { base + 1, invalid_bucket_id, 'Test', 42 }
1752+
local tuple_clean = { base + 2, box.NULL, 'Test', 42 }
1753+
local obj_bad = { id = base + 1001, bucket_id = invalid_bucket_id, name = 'Test', age = 42 }
1754+
local obj_clean = { id = base + 1002, name = 'Test', age = 42 }
1755+
local ops = { { '=', 'name', 'NewName' } }
17701756

1771-
{'crud.upsert_object', {'customers', object, operations, {}}},
1772-
{'crud.upsert_object', {'customers', object_clean, operations, {bucket_id = invalid_bucket_id}}},
1773-
1774-
{'crud.update', {'customers', key, operations, {bucket_id = invalid_bucket_id}}},
1775-
{'crud.delete', {'customers', key, {bucket_id = invalid_bucket_id}}},
1757+
local crud_calls = {
1758+
{
1759+
func = 'crud.insert',
1760+
args = { 'customers', tuple_bad, {} },
1761+
expected = ERR_IN_DATA
1762+
},
1763+
{
1764+
func = 'crud.insert',
1765+
args = { 'customers', tuple_clean, { bucket_id = invalid_bucket_id } },
1766+
expected = ERR_IN_OPTS
1767+
},
1768+
{
1769+
func = 'crud.insert_object',
1770+
args = { 'customers', obj_bad, {} },
1771+
expected = ERR_IN_DATA
1772+
},
1773+
{
1774+
func = 'crud.insert_object',
1775+
args = { 'customers', obj_clean, { bucket_id = invalid_bucket_id } },
1776+
expected = ERR_IN_OPTS
1777+
},
1778+
{
1779+
func = 'crud.replace',
1780+
args = { 'customers', { base + 3, invalid_bucket_id, 'Test', 42 }, {} },
1781+
expected = ERR_IN_DATA
1782+
},
1783+
{
1784+
func = 'crud.replace',
1785+
args = { 'customers', { base + 4, box.NULL, 'Test', 42 }, { bucket_id = invalid_bucket_id } },
1786+
expected = ERR_IN_OPTS
1787+
},
1788+
{
1789+
func = 'crud.replace_object',
1790+
args = { 'customers', { id = base + 1003, bucket_id = invalid_bucket_id, name = 'Test', age = 42 }, {} },
1791+
expected = ERR_IN_DATA
1792+
},
1793+
{
1794+
func = 'crud.replace_object',
1795+
args = { 'customers', { id = base + 1004, name = 'Test', age = 42 }, { bucket_id = invalid_bucket_id } },
1796+
expected = ERR_IN_OPTS
1797+
},
1798+
{
1799+
func = 'crud.upsert',
1800+
args = { 'customers', { base + 5, invalid_bucket_id, 'Test', 42 }, ops, {} },
1801+
expected = ERR_IN_DATA
1802+
},
1803+
{
1804+
func = 'crud.upsert',
1805+
args = { 'customers', { base + 6, box.NULL, 'Test', 42 }, ops, { bucket_id = invalid_bucket_id } },
1806+
expected = ERR_IN_OPTS
1807+
},
1808+
{
1809+
func = 'crud.upsert_object',
1810+
args = { 'customers',
1811+
{ id = base + 1005, bucket_id = invalid_bucket_id, name = 'Test', age = 42 }, ops, {}
1812+
},
1813+
expected = ERR_IN_DATA
1814+
},
1815+
{
1816+
func = 'crud.upsert_object',
1817+
args = { 'customers',
1818+
{ id = base + 1006, name = 'Test', age = 42 }, ops, { bucket_id = invalid_bucket_id }
1819+
},
1820+
expected = ERR_IN_OPTS
1821+
},
1822+
{
1823+
func = 'crud.update',
1824+
args = { 'customers', base + 7, ops, { bucket_id = invalid_bucket_id } },
1825+
expected = ERR_IN_OPTS
1826+
},
1827+
{
1828+
func = 'crud.delete',
1829+
args = { 'customers', base + 8, { bucket_id = invalid_bucket_id } },
1830+
expected = ERR_IN_OPTS
1831+
},
17761832
}
17771833

17781834
for _, call in ipairs(crud_calls) do
1779-
local func, args = call[1], call[2]
1780-
local _, err = g.router:call(func, args)
1781-
t.assert_str_contains(err.err or err[1].err, expected_err, func)
1835+
local _, err = g.router:call(call.func, call.args)
1836+
t.assert_str_contains(err.err or err[1].err, call.expected, call.func)
17821837
end
17831838
end
17841839

17851840
pgroup.test_invalid_bucket_id_many_operations = function(g)
17861841
local invalid_bucket_id = 'bad-id'
1787-
local expected_err = string.format('Invalid bucket_id: expected unsigned, got %s', type(invalid_bucket_id))
1842+
local expected_err = string.format('Invalid bucket_id in data: expected unsigned, got %s', type(invalid_bucket_id))
17881843

17891844
local many_calls = {
17901845
{
@@ -1818,7 +1873,7 @@ end
18181873

18191874
pgroup.test_invalid_bucket_id_object_many_operations = function(g)
18201875
local invalid_bucket_id = 'bad-id'
1821-
local expected_err = string.format('Invalid bucket_id: expected unsigned, got %s', type(invalid_bucket_id))
1876+
local expected_err = string.format('Invalid bucket_id in data: expected unsigned, got %s', type(invalid_bucket_id))
18221877

18231878
local object_many_calls = {
18241879
{
@@ -1860,7 +1915,7 @@ pgroup.test_get_invalid_bucket_id = function(g)
18601915

18611916
for _, bucket_id in ipairs(invalid_values) do
18621917
local expected_err = string.format(
1863-
"Invalid bucket_id: expected unsigned, got %s",
1918+
"Invalid bucket_id in opts: expected unsigned, got %s",
18641919
type(bucket_id)
18651920
)
18661921
local result, err = g.router:call('crud.get', {
@@ -1871,4 +1926,3 @@ pgroup.test_get_invalid_bucket_id = function(g)
18711926
t.assert_str_contains(err.err or err.str, expected_err)
18721927
end
18731928
end
1874-

0 commit comments

Comments
 (0)