Skip to content

Commit 1749af5

Browse files
test: support Tarantool 3.0 cluster from config
After this patch, it is possible to start a Tarantool 3.0 cluster from the config. It doesn't yet integrated with common test matrix yet. The tests are basic and shallow since it would be tested against the whole crud test suite in the next commits of the patchset. Part of #412 Part of #415
1 parent f23150d commit 1749af5

File tree

9 files changed

+1019
-25
lines changed

9 files changed

+1019
-25
lines changed

test/helper.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,4 +1023,19 @@ function helpers.wait_rw()
10231023
end
10241024
end
10251025

1026+
function helpers.is_tarantool_config_supported()
1027+
local tarantool_version = luatest_utils.get_tarantool_version()
1028+
return luatest_utils.version_ge(tarantool_version, luatest_utils.version(3, 0, 0))
1029+
end
1030+
1031+
function helpers.is_tarantool_config_supported()
1032+
local tarantool_version = luatest_utils.get_tarantool_version()
1033+
return luatest_utils.version_ge(tarantool_version, luatest_utils.version(3, 0, 0))
1034+
end
1035+
1036+
function helpers.skip_if_tarantool_config_unsupported()
1037+
t.skip_if(not helpers.is_tarantool_config_supported(),
1038+
("Tarantool %s does not support starting from config"):format(box.info.version))
1039+
end
1040+
10261041
return helpers

test/path.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
local fio = require('fio')
2+
3+
local ROOT = fio.dirname(fio.dirname(fio.abspath(package.search('test.path'))))
4+
5+
local LUA_PATH = ROOT .. '/?.lua;' ..
6+
ROOT .. '/?/init.lua;' ..
7+
ROOT .. '/.rocks/share/tarantool/?.lua;' ..
8+
ROOT .. '/.rocks/share/tarantool/?/init.lua'
9+
10+
return {
11+
ROOT = ROOT,
12+
LUA_PATH = LUA_PATH,
13+
}

test/scenario.lua

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
local t = require('luatest')
2+
3+
-- Autoincrement ids so each run actually checks
4+
-- insert/get without intermediate truncates.
5+
local last_id = 1
6+
local function test_basic_insert_get_object(cg)
7+
cg.cluster:server('router'):exec(function(id)
8+
local crud = require('crud')
9+
10+
local _, err = crud.insert_object('customers',
11+
{id = id, name = 'Vincent Brooks', age = 32},
12+
{noreturn = true}
13+
)
14+
t.assert_equals(err, nil)
15+
16+
local result, err = crud.get('customers', id, {mode = 'write'})
17+
t.assert_equals(err, nil)
18+
t.assert_equals(#result.rows, 1, "Tuple found")
19+
20+
local objects, err = crud.unflatten_rows(result.rows, result.metadata)
21+
t.assert_equals(err, nil)
22+
t.assert_equals(objects[1].name, 'Vincent Brooks')
23+
t.assert_equals(objects[1].age, 32)
24+
end, {last_id})
25+
last_id = last_id + 1
26+
end
27+
28+
return {
29+
test_basic_insert_get_object = test_basic_insert_get_object,
30+
}

test/tarantool3_helpers/cluster.lua

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
local checks = require('checks')
2+
local fun = require('fun')
3+
local yaml = require('yaml')
4+
5+
local t = require('luatest')
6+
7+
local vtest = require('test.vshard_helpers.vtest')
8+
local treegen = require('test.tarantool3_helpers.treegen')
9+
local server_helper = require('test.tarantool3_helpers.server')
10+
local utils = require('test.tarantool3_helpers.utils')
11+
12+
local Cluster = {}
13+
14+
-- Inspired by
15+
-- https://github.com/tarantool/cartridge/blob/b9dc61e61bb85e75b7da7dc8f369867c0d3786c4/cartridge/test-helpers/cluster.lua
16+
-- together with
17+
-- https://github.com/tarantool/tarantool/blob/1a5e3bf3c3badd14ffc37b2b31e47554e4778cde/test/config-luatest/basic_test.lua#L39-L67
18+
19+
function Cluster:inherit(object)
20+
setmetatable(object, self)
21+
self.__index = self
22+
return object
23+
end
24+
25+
function Cluster:new(object)
26+
checks('table', {
27+
config = 'table',
28+
modules = '?table',
29+
env = '?table',
30+
crud_init = '?boolean',
31+
router_wait_until_ready = '?string',
32+
storage_wait_until_ready = '?string',
33+
})
34+
35+
self:inherit(object)
36+
object:initialize()
37+
return object
38+
end
39+
40+
local function write_config(dir, config)
41+
return treegen.write_script(dir, 'config.yaml', yaml.encode(config))
42+
end
43+
44+
function Cluster:initialize()
45+
self.servers = {}
46+
self.dirs = {}
47+
48+
self.treegen = {}
49+
treegen.init(self.treegen)
50+
51+
for _, group in pairs(self.config.groups) do
52+
for _, replicaset in pairs(group.replicasets) do
53+
local is_router = utils.is_replicaset_a_sharding_router(group, replicaset)
54+
local is_storage = utils.is_replicaset_a_sharding_storage(group, replicaset)
55+
56+
for alias, _ in pairs(replicaset.instances) do
57+
local dir = treegen.prepare_directory(self.treegen, {}, {})
58+
59+
local config_file = write_config(dir, self.config)
60+
61+
for name, content in pairs(self.modules or {}) do
62+
treegen.write_script(dir, name .. '.lua', content)
63+
end
64+
65+
local opts = {config_file = config_file, chdir = dir}
66+
67+
local server = server_helper:new(fun.chain(opts, {alias = alias}):tomap())
68+
69+
for k, v in pairs(self.env or {}) do
70+
server.env[k] = v
71+
end
72+
73+
server:set_router_tag(is_router)
74+
server:set_storage_tag(is_storage)
75+
76+
table.insert(self.servers, server)
77+
self.dirs[server] = dir
78+
end
79+
end
80+
end
81+
82+
self.main_server = self.servers[1]
83+
84+
return self
85+
end
86+
87+
function Cluster:set_etalon_bucket_balance()
88+
local masters = {}
89+
local etalon_balance = {}
90+
local replicaset_count = 0
91+
92+
for _, group in pairs(self.config.groups) do
93+
for rs_id, rs in pairs(group.replicasets) do
94+
if not utils.is_replicaset_a_sharding_storage(group, rs) then
95+
goto continue
96+
end
97+
98+
local rs_uuid
99+
if (rs.database or {}).replicaset_uuid ~= nil then
100+
rs_uuid = rs.database.replicaset_uuid
101+
else
102+
rs_uuid = vtest.replicaset_name_to_uuid(rs_id)
103+
end
104+
105+
local leader_id = rs.leader
106+
assert(leader_id ~= nil, "Only explicit leader is supported now.")
107+
108+
masters[rs_uuid] = self:server(leader_id)
109+
110+
local weight = 1 -- Only equal weight is supported now.
111+
112+
etalon_balance[rs_uuid] = {
113+
weight = weight,
114+
}
115+
replicaset_count = replicaset_count + 1
116+
117+
::continue::
118+
end
119+
end
120+
t.assert_not_equals(masters, {}, 'have masters')
121+
122+
local bucket_count = self.config.sharding.bucket_count
123+
vtest.distribute_etalon_buckets(etalon_balance, masters, replicaset_count, bucket_count)
124+
end
125+
126+
function Cluster:method_on_replicaset(method, config_replicaset, func, args)
127+
for alias, _ in pairs(config_replicaset.instances) do
128+
local server = self:server(alias)
129+
server[method](server, func, args)
130+
end
131+
end
132+
133+
function Cluster:exec_on_replicaset(config_replicaset, func, args)
134+
self:method_on_replicaset('exec', config_replicaset, func, args)
135+
end
136+
137+
function Cluster:eval_on_replicaset(config_replicaset, func, args)
138+
self:method_on_replicaset('eval', config_replicaset, func, args)
139+
end
140+
141+
local function bootstrap_vshard_router()
142+
local vshard = require('vshard')
143+
vshard.router.bootstrap()
144+
end
145+
146+
function Cluster:bootstrap_vshard_routers()
147+
for _, group in pairs(self.config.groups) do
148+
for _, rs in pairs(group.replicasets) do
149+
if utils.is_replicaset_a_sharding_router(group, rs) then
150+
self:exec_on_replicaset(rs, bootstrap_vshard_router)
151+
end
152+
end
153+
end
154+
end
155+
156+
local function bootstrap_crud_router()
157+
local crud = require('crud')
158+
crud.init_router()
159+
end
160+
161+
local function bootstrap_crud_storage()
162+
local crud = require('crud')
163+
crud.init_storage{
164+
wait_until_ready = false,
165+
async = true,
166+
}
167+
end
168+
169+
local function wait_until_crud_storage_ready()
170+
local crud = require('crud')
171+
crud.wait_until_storage_ready()
172+
end
173+
174+
function Cluster:bootstrap_crud()
175+
for _, group in pairs(self.config.groups) do
176+
for _, rs in pairs(group.replicasets) do
177+
if utils.is_replicaset_a_sharding_router(group, rs) then
178+
self:exec_on_replicaset(rs, bootstrap_crud_router)
179+
end
180+
181+
if utils.is_replicaset_a_sharding_storage(group, rs) then
182+
self:exec_on_replicaset(rs, bootstrap_crud_storage)
183+
end
184+
end
185+
end
186+
187+
for _, group in pairs(self.config.groups) do
188+
for _, rs in pairs(group.replicasets) do
189+
if utils.is_replicaset_a_sharding_storage(group, rs) then
190+
self:exec_on_replicaset(rs, wait_until_crud_storage_ready)
191+
end
192+
end
193+
end
194+
end
195+
196+
function Cluster:wait_for_leaders_rw()
197+
for _, group in pairs(self.config.groups) do
198+
for _, rs in pairs(group.replicasets) do
199+
local leader_id = rs.leader
200+
local leader = self:server(leader_id)
201+
202+
leader:wait_for_rw()
203+
end
204+
end
205+
end
206+
207+
function Cluster:start()
208+
for _, server in ipairs(self.servers) do
209+
server:start({wait_until_ready = false})
210+
end
211+
212+
return self:wait_until_ready()
213+
end
214+
215+
function Cluster:wait_until_ready()
216+
for _, server in ipairs(self.servers) do
217+
server:wait_until_ready()
218+
end
219+
220+
for _, server in ipairs(self.servers) do
221+
t.assert_equals(server:eval('return box.info.name'), server.alias)
222+
end
223+
224+
self:wait_for_leaders_rw()
225+
226+
self:set_etalon_bucket_balance()
227+
self:bootstrap_vshard_routers()
228+
229+
if self.crud_init then
230+
self:bootstrap_crud()
231+
end
232+
233+
for _, group in pairs(self.config.groups) do
234+
for _, rs in pairs(group.replicasets) do
235+
if self.router_wait_until_ready ~= nil
236+
and utils.is_replicaset_a_sharding_router(group, rs) then
237+
self:eval_on_replicaset(rs, self.router_wait_until_ready)
238+
end
239+
240+
if self.storage_wait_until_ready ~= nil
241+
and utils.is_replicaset_a_sharding_storage(group, rs) then
242+
self:eval_on_replicaset(rs, self.storage_wait_until_ready)
243+
end
244+
end
245+
end
246+
247+
return self
248+
end
249+
250+
function Cluster:cfg(new_config)
251+
if new_config ~= nil then
252+
self:reload_config(new_config)
253+
end
254+
255+
return table.deepcopy(self.config)
256+
end
257+
258+
function Cluster:reload_config(new_config)
259+
t.assert_equals(new_config.groups, self.config.groups, 'groups reload is not supported yet')
260+
261+
for _, server in ipairs(self.servers) do
262+
write_config(self.dirs[server], new_config)
263+
end
264+
265+
for _, server in ipairs(self.servers) do
266+
server:exec(function()
267+
require('config'):reload()
268+
end)
269+
end
270+
271+
self.config = new_config
272+
end
273+
274+
function Cluster:stop()
275+
for _, server in ipairs(self.servers) do
276+
server:stop()
277+
end
278+
279+
return self
280+
end
281+
282+
function Cluster:drop()
283+
self:stop()
284+
treegen.clean(self.treegen)
285+
286+
return self
287+
end
288+
289+
function Cluster:server(alias)
290+
for _, server in ipairs(self.servers) do
291+
if server.alias == alias then
292+
return server
293+
end
294+
end
295+
error('Server ' .. alias .. ' not found', 2)
296+
end
297+
298+
return Cluster

0 commit comments

Comments
 (0)