test_ydb_backup.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. # -*- coding: utf-8 -*-
  2. from ydb.tests.library.common import yatest_common
  3. from ydb.tests.library.harness.kikimr_cluster import kikimr_cluster_factory
  4. from ydb.tests.ydb_sdk_import import ydb
  5. from hamcrest import assert_that, is_, is_not, contains_inanyorder, has_item, has_items
  6. import os
  7. import logging
  8. import pytest
  9. logger = logging.getLogger(__name__)
  10. def backup_bin():
  11. return yatest_common.binary_path("ydb/apps/ydb/ydb")
  12. def upsert_simple(session, full_path):
  13. path, table = os.path.split(full_path)
  14. session.transaction().execute(
  15. """
  16. PRAGMA TablePathPrefix("{0}");
  17. UPSERT INTO {1} (`id`, `number`, `string`, `fixed_point`) VALUES (2, 6, "pen", CAST("2.4" AS Decimal(22,9)));
  18. UPSERT INTO {1} (`id`, `string`, `fixed_point`) VALUES (3, "pineapple", CAST("3.5" AS Decimal(22,9)));
  19. UPSERT INTO {1} (`id`, `number`, `fixed_point`) VALUES (5, 12, CAST("512.6" AS Decimal(22,9)));
  20. UPSERT INTO {1} (`id`, `number`, `string` ) VALUES (7, 15, "pen" );
  21. """.format(path, table),
  22. commit_tx=True,
  23. )
  24. def output_path(*args):
  25. path = os.path.join(yatest_common.output_path(), *args)
  26. os.makedirs(path, exist_ok=False)
  27. return path
  28. def list_to_string(arr, formatter=lambda x: x):
  29. string = "{"
  30. needsComma = False
  31. for x in arr:
  32. if needsComma:
  33. string += ", "
  34. needsComma = True
  35. string += formatter(x)
  36. string += "}"
  37. return string
  38. def columns_to_string(columns):
  39. return list_to_string(columns, lambda col: col.name + ":" + str(col.type.item).strip())
  40. def create_table_with_data(session, path):
  41. path = "/Root/" + path
  42. session.create_table(
  43. path,
  44. ydb.TableDescription()
  45. .with_column(ydb.Column("id", ydb.OptionalType(ydb.PrimitiveType.Uint32)))
  46. .with_column(ydb.Column("number", ydb.OptionalType(ydb.PrimitiveType.Uint64)))
  47. .with_column(ydb.Column("string", ydb.OptionalType(ydb.PrimitiveType.String)))
  48. .with_column(ydb.Column("fixed_point", ydb.OptionalType(ydb.DecimalType())))
  49. .with_primary_keys("id")
  50. )
  51. upsert_simple(session, path)
  52. def is_tables_the_same(session, path_left, path_right, check_data=True):
  53. table_desc_left = session.describe_table(path_left)
  54. table_desc_right = session.describe_table(path_right)
  55. if (
  56. sorted(table_desc_left.columns, key=lambda x: x.name) != sorted(table_desc_right.columns, key=lambda x: x.name)
  57. or table_desc_left.primary_key != table_desc_right.primary_key):
  58. left_cols = columns_to_string(table_desc_left.columns)
  59. left_pk = list_to_string(table_desc_left.primary_key)
  60. right_cols = columns_to_string(table_desc_right.columns)
  61. right_pk = list_to_string(table_desc_right.primary_key)
  62. logging.debug("Tables descriptions (is not the same)!" +
  63. "\npath_left# " + path_left + " has columns# " + left_cols + " primary_key# " + left_pk +
  64. "\npath_right# " + path_right + " has columns# " + right_cols + " primary_key# " + right_pk)
  65. return False
  66. if not check_data:
  67. return True
  68. table_it_left = session.read_table(path_left, ordered=True)
  69. table_it_right = session.read_table(path_right, ordered=True)
  70. left_rows = []
  71. right_rows = []
  72. processed_rows = 0
  73. while True:
  74. if len(left_rows) == 0:
  75. try:
  76. left_rows = next(table_it_left).rows
  77. except StopIteration:
  78. if len(right_rows) == 0:
  79. return True
  80. else:
  81. logging.debug(path_left + " is shorter than " + path_right + " processed# " + str(processed_rows) +
  82. " len(right_rows)#" + str(len(right_rows)))
  83. return False
  84. if len(right_rows) == 0:
  85. try:
  86. right_rows = next(table_it_right).rows
  87. except StopIteration:
  88. if len(left_rows) == 0:
  89. return True
  90. else:
  91. logging.debug(path_right + " is shorter than " + path_left + " processed# " + str(processed_rows) +
  92. " len(left_rows)#" + str(len(left_rows)))
  93. return False
  94. rows_to_process = min(len(left_rows), len(right_rows))
  95. for i in range(rows_to_process):
  96. if left_rows[i] != right_rows[i]:
  97. logging.debug(str(left_rows[i]) + " != " + str(right_rows[i]))
  98. return False
  99. processed_rows += rows_to_process
  100. left_rows = left_rows[rows_to_process:]
  101. right_rows = right_rows[rows_to_process:]
  102. return True
  103. def list_all_dirs(prefix, path=""):
  104. paths = []
  105. full_path = os.path.join(prefix, path)
  106. logger.debug("prefix# " + prefix + " path# " + path)
  107. for item in os.listdir(full_path):
  108. item_path = os.path.join(full_path, item)
  109. if os.path.isdir(item_path):
  110. paths.append(os.path.join(path, item))
  111. paths += list_all_dirs(prefix, os.path.join(path, item))
  112. else:
  113. # don't list regular files
  114. pass
  115. return paths
  116. class BaseTestBackupInFiles(object):
  117. @classmethod
  118. def setup_class(cls):
  119. cls.cluster = kikimr_cluster_factory()
  120. cls.cluster.start()
  121. cls.root_dir = "/Root"
  122. driver_config = ydb.DriverConfig(
  123. database="/Root",
  124. endpoint="%s:%s" % (cls.cluster.nodes[1].host, cls.cluster.nodes[1].port))
  125. cls.driver = ydb.Driver(driver_config)
  126. cls.driver.wait(timeout=4)
  127. @classmethod
  128. def teardown_class(cls):
  129. cls.cluster.stop()
  130. @pytest.fixture(autouse=True, scope='class')
  131. @classmethod
  132. def set_test_name(cls, request):
  133. cls.test_name = request.node.name
  134. @classmethod
  135. def create_backup(cls, path, expected_dirs, check_data, additional_args=[]):
  136. _, name = os.path.split(path)
  137. backup_files_dir = output_path(cls.test_name, "backup_files_dir_" + path.replace("/", "_"))
  138. execution = yatest_common.execute(
  139. [
  140. backup_bin(),
  141. "--verbose",
  142. "--endpoint", "grpc://localhost:%d" % cls.cluster.nodes[1].grpc_port,
  143. "--database", "/Root",
  144. "tools", "dump",
  145. "--path", os.path.join('/Root', path),
  146. "--output", backup_files_dir
  147. ] +
  148. additional_args
  149. )
  150. logger.debug("std_out:\n" + execution.std_out.decode('utf-8'))
  151. list_all_dirs(backup_files_dir)
  152. logger.debug("list_all_dirs(backup_files_dir)# " + str(list_all_dirs(backup_files_dir)))
  153. logger.debug("expected_dirs# " + str(expected_dirs))
  154. assert_that(
  155. list_all_dirs(backup_files_dir),
  156. has_items(*expected_dirs)
  157. )
  158. for _dir in expected_dirs:
  159. if check_data:
  160. assert_that(
  161. os.listdir(backup_files_dir + "/" + _dir),
  162. contains_inanyorder("data_00.csv", "scheme.pb")
  163. )
  164. else:
  165. assert_that(
  166. os.listdir(backup_files_dir + "/" + _dir),
  167. has_item("scheme.pb")
  168. )
  169. class TestBackupSingle(BaseTestBackupInFiles):
  170. def test_single_table_backup(self):
  171. session = self.driver.table_client.session().create()
  172. # Create table
  173. path = "table"
  174. create_table_with_data(session, path)
  175. # Backup table
  176. self.create_backup(path, [path], False)
  177. assert_that(
  178. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  179. is_(["table", ".sys"])
  180. )
  181. class TestBaseSingleFromDifPlaces(BaseTestBackupInFiles):
  182. def test_single_table_backup_from_different_places(self):
  183. session = self.driver.table_client.session().create()
  184. # Create table
  185. self.driver.scheme_client.make_directory(
  186. '/Root/folder'
  187. )
  188. self.driver.scheme_client.make_directory(
  189. '/Root/folder/sub_folder'
  190. )
  191. tables_paths = [
  192. "first",
  193. "second",
  194. "folder/third",
  195. "folder/fourth",
  196. "folder/sub_folder/fifth",
  197. ]
  198. for path in tables_paths:
  199. create_table_with_data(session, path)
  200. # Backup table
  201. for path in tables_paths:
  202. _, table_name = os.path.split(path)
  203. self.create_backup(path, [table_name], True)
  204. class TestRecursiveNonConsistent(BaseTestBackupInFiles):
  205. def test_recursive_table_backup_from_different_places(self):
  206. session = self.driver.table_client.session().create()
  207. # Create table
  208. self.driver.scheme_client.make_directory(
  209. '/Root/folder'
  210. )
  211. self.driver.scheme_client.make_directory(
  212. '/Root/folder/sub_folder'
  213. )
  214. tables_paths = [
  215. "first",
  216. "second",
  217. "folder/third",
  218. "folder/fourth",
  219. "folder/sub_folder/fifth",
  220. ]
  221. for path in tables_paths:
  222. create_table_with_data(session, path)
  223. # Backup all tables from Root recursively
  224. self.create_backup("/Root", tables_paths, True, ["--consistency-level", "table"])
  225. # Backup single table
  226. self.create_backup("first", ["first"], True, ["--consistency-level", "table"])
  227. self.create_backup("folder/third", ["third"], True, ["--consistency-level", "table"])
  228. # Backup tables from folder recursively
  229. tables_paths = [
  230. "third",
  231. "fourth",
  232. "sub_folder/fifth",
  233. ]
  234. self.create_backup("folder", tables_paths, True, ["--consistency-level", "table"])
  235. # Backup table from sub_folder recursively
  236. tables_paths = [
  237. "fifth",
  238. ]
  239. self.create_backup("folder/sub_folder", tables_paths, True, ["--consistency-level", "table"])
  240. class TestRecursiveSchemeOnly(BaseTestBackupInFiles):
  241. def test_recursive_table_backup_from_different_places(self):
  242. session = self.driver.table_client.session().create()
  243. # Create table
  244. self.driver.scheme_client.make_directory(
  245. '/Root/folder'
  246. )
  247. self.driver.scheme_client.make_directory(
  248. '/Root/folder/sub_folder'
  249. )
  250. tables_paths = [
  251. "first",
  252. "second",
  253. "folder/third",
  254. "folder/fourth",
  255. "folder/sub_folder/fifth",
  256. ]
  257. for path in tables_paths:
  258. create_table_with_data(session, path)
  259. # Backup all tables from Root recursively
  260. self.create_backup("/Root", tables_paths, False, ["--scheme-only"])
  261. # Backup single table
  262. self.create_backup("first", ["first"], False, ["--scheme-only"])
  263. self.create_backup("folder/third", ["third"], False, ["--scheme-only"])
  264. # Backup tables from folder recursively
  265. tables_paths = [
  266. "third",
  267. "fourth",
  268. "sub_folder/fifth",
  269. ]
  270. self.create_backup("folder", tables_paths, False, ["--scheme-only"])
  271. # Backup table from sub_folder recursively
  272. tables_paths = [
  273. "fifth",
  274. ]
  275. self.create_backup("folder/sub_folder", tables_paths, False, ["--scheme-only"])
  276. class TestRecursiveConsistent(BaseTestBackupInFiles):
  277. def test_recursive_table_backup_from_different_places(self):
  278. session = self.driver.table_client.session().create()
  279. # Create table
  280. self.driver.scheme_client.make_directory(
  281. '/Root/folder'
  282. )
  283. self.driver.scheme_client.make_directory(
  284. '/Root/folder/sub_folder'
  285. )
  286. tables_paths = [
  287. "first",
  288. "second",
  289. "folder/third",
  290. "folder/fourth",
  291. "folder/sub_folder/fifth",
  292. ]
  293. for path in tables_paths:
  294. create_table_with_data(session, path)
  295. # Backup all tables from Root recursively
  296. self.create_backup("/Root", tables_paths, True, ["--consistency-level", "database"])
  297. # Backup single table
  298. self.create_backup("first", ["first"], True, ["--consistency-level", "database"])
  299. self.create_backup("folder/third", ["third"], True, ["--consistency-level", "database"])
  300. # Backup tables from folder recursively
  301. tables_paths = [
  302. "third",
  303. "fourth",
  304. "sub_folder/fifth",
  305. ]
  306. self.create_backup("folder", tables_paths, True, ["--consistency-level", "database"])
  307. # Backup table from sub_folder recursively
  308. tables_paths = [
  309. "fifth",
  310. ]
  311. self.create_backup("folder/sub_folder", tables_paths, True, ["--consistency-level", "database"])
  312. class TestSingleBackupRestore(BaseTestBackupInFiles):
  313. def test_single_table_with_data_backup_restore(self):
  314. self.test_single_table_with_data_backup_restore_impl(False)
  315. self.test_single_table_with_data_backup_restore_impl(True)
  316. @classmethod
  317. def test_single_table_with_data_backup_restore_impl(self, use_bulk_upsert):
  318. self.driver.scheme_client.make_directory(
  319. '/Root/folder'
  320. )
  321. postfix = '_bulk_upsert' if use_bulk_upsert else ''
  322. session = self.driver.table_client.session().create()
  323. # Create table and fill with data
  324. create_table_with_data(session, "folder/table")
  325. # Backup table
  326. backup_files_dir = output_path(self.test_name, 'test_single_table_with_data_backup_restore' + postfix, "backup_files_dir")
  327. yatest_common.execute(
  328. [
  329. backup_bin(),
  330. "--verbose",
  331. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  332. "--database", "/Root",
  333. "tools", "dump",
  334. "--path", "/Root/folder",
  335. "--output", backup_files_dir
  336. ]
  337. )
  338. assert_that(
  339. os.listdir(backup_files_dir),
  340. is_(["table"])
  341. )
  342. assert_that(
  343. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  344. is_(["folder", ".sys"])
  345. )
  346. # Restore table
  347. restore_cmd = [
  348. backup_bin(),
  349. "--verbose",
  350. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  351. "--database", "/Root",
  352. "tools", "restore",
  353. "--path", "/Root/restored" + postfix,
  354. "--input", backup_files_dir
  355. ]
  356. if use_bulk_upsert:
  357. restore_cmd.append("--bulk-upsert")
  358. yatest_common.execute(restore_cmd)
  359. assert_that(
  360. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  361. contains_inanyorder("folder", "restored" + postfix, ".sys")
  362. )
  363. assert_that(
  364. [child.name for child in self.driver.scheme_client.list_directory("/Root/restored" + postfix).children],
  365. is_(["table"])
  366. )
  367. assert_that(
  368. is_tables_the_same(session, "/Root/folder/table", "/Root/restored" + postfix + "/table"),
  369. is_(True)
  370. )
  371. session.drop_table("/Root/restored" + postfix + "/table")
  372. self.driver.scheme_client.remove_directory("/Root/restored" + postfix)
  373. class TestBackupRestoreInRoot(BaseTestBackupInFiles):
  374. def test_table_backup_restore_in_root(self):
  375. self.driver.scheme_client.make_directory(
  376. '/Root/folder'
  377. )
  378. session = self.driver.table_client.session().create()
  379. # Create table and fill with data
  380. create_table_with_data(session, "folder/table")
  381. # Backup table
  382. backup_files_dir = output_path(self.test_name, 'test_single_table_with_data_backup_restore', "backup_files_dir")
  383. yatest_common.execute(
  384. [
  385. backup_bin(),
  386. "--verbose",
  387. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  388. "--database", "/Root",
  389. "tools", "dump",
  390. "--path", "/Root/folder",
  391. "--output", backup_files_dir
  392. ]
  393. )
  394. assert_that(
  395. os.listdir(backup_files_dir),
  396. is_(["table"])
  397. )
  398. assert_that(
  399. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  400. is_(["folder", ".sys"])
  401. )
  402. # Restore table
  403. yatest_common.execute(
  404. [
  405. backup_bin(),
  406. "--verbose",
  407. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  408. "--database", "/Root",
  409. "tools", "restore",
  410. "--path", "/Root/",
  411. "--input", backup_files_dir
  412. ]
  413. )
  414. assert_that(
  415. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  416. contains_inanyorder("folder", "table", ".sys")
  417. )
  418. assert_that(
  419. is_tables_the_same(session, "/Root/folder/table", "/Root/table"),
  420. is_(True)
  421. )
  422. class TestBackupRestoreInRootSchemeOnly(BaseTestBackupInFiles):
  423. def test_table_backup_restore_in_root_scheme_only(self):
  424. self.driver.scheme_client.make_directory(
  425. '/Root/folder'
  426. )
  427. session = self.driver.table_client.session().create()
  428. # Create table and fill with data
  429. create_table_with_data(session, "folder/table")
  430. # Backup table
  431. backup_files_dir = output_path(self.test_name, 'test_single_table_with_data_backup_restore', "backup_files_dir")
  432. yatest_common.execute(
  433. [
  434. backup_bin(),
  435. "--verbose",
  436. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  437. "--database", "/Root",
  438. "tools", "dump",
  439. "--scheme-only",
  440. "--path", "/Root/folder",
  441. "--output", backup_files_dir
  442. ]
  443. )
  444. assert_that(
  445. os.listdir(backup_files_dir),
  446. is_(["table"])
  447. )
  448. assert_that(
  449. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  450. is_(["folder", ".sys"])
  451. )
  452. # Restore table
  453. yatest_common.execute(
  454. [
  455. backup_bin(),
  456. "--verbose",
  457. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  458. "--database", "/Root",
  459. "tools", "restore",
  460. "--path", "/Root/",
  461. "--input", backup_files_dir
  462. ]
  463. )
  464. assert_that(
  465. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  466. contains_inanyorder("folder", "table", ".sys")
  467. )
  468. assert_that(
  469. is_tables_the_same(session, "/Root/folder/table", "/Root/table", False),
  470. is_(True)
  471. )
  472. class TestIncompleteBackup(BaseTestBackupInFiles):
  473. def test_incomplete_backup_will_not_be_restored(self):
  474. self.driver.scheme_client.make_directory(
  475. '/Root/folder'
  476. )
  477. session = self.driver.table_client.session().create()
  478. create_table_with_data(session, "folder/table")
  479. # Backup table
  480. backup_files_dir = output_path(self.test_name, "backup_files_dir")
  481. yatest_common.execute(
  482. [
  483. backup_bin(),
  484. "--verbose",
  485. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  486. "--database", "/Root",
  487. 'tools', 'dump',
  488. "--path", '/Root/folder',
  489. "--output", backup_files_dir
  490. ]
  491. )
  492. assert_that(
  493. os.listdir(backup_files_dir),
  494. is_(["table"])
  495. )
  496. assert_that(
  497. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  498. is_(["folder", ".sys"])
  499. )
  500. # Create "incomplete" file in folder with backup files
  501. open(os.path.join(backup_files_dir, "incomplete"), "w").close()
  502. open(os.path.join(backup_files_dir, "table", "incomplete"), "w").close()
  503. # Restore table and check that it fails without restoring anything
  504. execution = yatest_common.execute(
  505. [
  506. backup_bin(),
  507. "--verbose",
  508. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  509. "--database", "/Root",
  510. 'tools', 'restore',
  511. "--path", "/Root/restored",
  512. "--input", backup_files_dir
  513. ],
  514. check_exit_code=False
  515. )
  516. assert_that(
  517. execution.exit_code,
  518. is_not(0)
  519. )
  520. assert_that(
  521. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  522. is_(["folder", ".sys"])
  523. )
  524. assert_that(
  525. [child.name for child in self.driver.scheme_client.list_directory("/Root/folder").children],
  526. is_(["table"])
  527. )
  528. execution = yatest_common.execute(
  529. [
  530. backup_bin(),
  531. "--verbose",
  532. "--endpoint", "localhost:%d" % self.cluster.nodes[1].grpc_port,
  533. "--database", "/Root"
  534. 'tools', 'restore',
  535. "--path", "/Root/restored",
  536. "--input", os.path.join(backup_files_dir, "table")
  537. ],
  538. check_exit_code=False
  539. )
  540. assert_that(
  541. execution.exit_code,
  542. is_not(0)
  543. )
  544. assert_that(
  545. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  546. is_(["folder", ".sys"])
  547. )
  548. assert_that(
  549. [child.name for child in self.driver.scheme_client.list_directory("/Root/folder").children],
  550. is_(["table"])
  551. )
  552. class TestAlterBackupRestore(BaseTestBackupInFiles):
  553. def test_alter_table_with_data_backup_restore(self):
  554. self.driver.scheme_client.make_directory(
  555. '/Root/folder'
  556. )
  557. session = self.driver.table_client.session().create()
  558. # Create table and fill with data
  559. path = "/Root/folder/table"
  560. session.create_table(
  561. path,
  562. ydb.TableDescription()
  563. .with_column(ydb.Column("a", ydb.OptionalType(ydb.PrimitiveType.Uint32)))
  564. .with_column(ydb.Column("b", ydb.OptionalType(ydb.PrimitiveType.String)))
  565. .with_column(ydb.Column("c", ydb.OptionalType(ydb.PrimitiveType.Uint32)))
  566. .with_column(ydb.Column("d", ydb.OptionalType(ydb.PrimitiveType.String)))
  567. .with_column(ydb.Column("e", ydb.OptionalType(ydb.PrimitiveType.Uint32)))
  568. .with_column(ydb.Column("f", ydb.OptionalType(ydb.PrimitiveType.String)))
  569. .with_column(ydb.Column("g", ydb.OptionalType(ydb.PrimitiveType.Uint32)))
  570. .with_column(ydb.Column("h", ydb.OptionalType(ydb.PrimitiveType.String)))
  571. .with_primary_keys("a")
  572. )
  573. prefix, table = os.path.split(path)
  574. session.transaction().execute(
  575. """
  576. PRAGMA TablePathPrefix("{0}");
  577. UPSERT INTO {1} (a, b, c, d, e, f, g, h) VALUES (5, "b", 5, "b", 5, "b", 5, "b");
  578. """.format(prefix, table),
  579. commit_tx=True,
  580. )
  581. session.alter_table(
  582. path,
  583. [],
  584. ['b']
  585. )
  586. # Backup table
  587. backup_files_dir = output_path(self.test_name, 'test_single_table_with_data_backup_restore', "backup_files_dir")
  588. yatest_common.execute(
  589. [
  590. backup_bin(),
  591. "--verbose",
  592. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  593. "--database", "/Root",
  594. "tools", "dump",
  595. "--path", "/Root/folder",
  596. "--output", backup_files_dir
  597. ]
  598. )
  599. assert_that(
  600. os.listdir(backup_files_dir),
  601. is_(["table"])
  602. )
  603. assert_that(
  604. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  605. is_(["folder", ".sys"])
  606. )
  607. # Restore table
  608. yatest_common.execute(
  609. [
  610. backup_bin(),
  611. "--verbose",
  612. "--endpoint", "grpc://localhost:%d" % self.cluster.nodes[1].grpc_port,
  613. "--database", "/Root",
  614. "tools", "restore",
  615. "--path", "/Root/restored",
  616. "--input", backup_files_dir
  617. ]
  618. )
  619. assert_that(
  620. [child.name for child in self.driver.scheme_client.list_directory("/Root").children],
  621. contains_inanyorder("folder", "restored", ".sys")
  622. )
  623. assert_that(
  624. [child.name for child in self.driver.scheme_client.list_directory("/Root/restored").children],
  625. is_(["table"])
  626. )
  627. assert_that(
  628. is_tables_the_same(session, "/Root/folder/table", "/Root/restored/table"),
  629. is_(True)
  630. )