diff options
| author | Pavel <[email protected]> | 2025-06-24 13:29:25 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-06-24 13:29:25 +0300 |
| commit | 4541608b62176767f43fb9aabdc8cb5095af6283 (patch) | |
| tree | 89a87f37e573fa98c4ac1ba5109f73c222bd4136 | |
| parent | 3a99069cf3656d577efeeeb64a831926bf670080 (diff) | |
Custom compatibility tags (#19415) (#19610)
| -rw-r--r-- | .github/workflows/regression_run_compatibility.yml | 28 | ||||
| -rw-r--r-- | ydb/tests/compatibility/README.md | 38 | ||||
| -rw-r--r-- | ydb/tests/compatibility/ya.make | 3 | ||||
| -rw-r--r-- | ydb/tests/library/compatibility/binaries/downloader/__main__.py | 38 | ||||
| -rw-r--r-- | ydb/tests/library/compatibility/binaries/ya.make | 34 | ||||
| -rw-r--r-- | ydb/tests/library/compatibility/fixtures.py | 92 |
6 files changed, 145 insertions, 88 deletions
diff --git a/.github/workflows/regression_run_compatibility.yml b/.github/workflows/regression_run_compatibility.yml index 12eca6795f6..5134c969c71 100644 --- a/.github/workflows/regression_run_compatibility.yml +++ b/.github/workflows/regression_run_compatibility.yml @@ -1,16 +1,27 @@ name: Regression-run_compatibility +run-name: >- + ${{ + inputs.initial_version_ref != '' && inputs.initial_version_ref || 'default-init'}} -> ${{ + inputs.inter_version_ref != '' && inputs.inter_version_ref || 'default-inter'}} -> ${{ + inputs.target_version_ref != '' && inputs.target_version_ref || 'default-target'}} on: schedule: - cron: "0 23 * * *" # At 23:00 every day workflow_dispatch: inputs: - use_default_branches: - description: 'If true, start main and all current stable branches. If false, start only the selected branch.' - type: boolean + initial_version_ref: + description: Initial(oldest) version (ex. stable-24-4, should exist on S3) + type: string + required: false + inter_version_ref: + description: Intermediate version (ex. stable-25-1-2/25.1.1.18, should exist on S3) + type: string + required: false + target_version_ref: + description: Target(newest) version ("current" - compiles binary from the chosen branch) + type: string required: false - default: true - jobs: main: name: Regression-run_compatibility @@ -22,5 +33,10 @@ jobs: build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/tests/compatibility/ - branches: ${{ (inputs.use_default_branches == true || github.event_name == 'schedule') && '["main", "stable-25-1", "stable-25-1-analytics"]' || github.ref_name }} + branches: ${{ github.ref_name }} build_preset: ${{ matrix.build_preset }} + additional_ya_make_args: >- + ${{ + inputs.initial_version_ref != '' && format(' -DYDB_COMPAT_INIT_REF={0} ', inputs.initial_version_ref) || ''}}${{ + inputs.inter_version_ref != '' && format(' -DYDB_COMPAT_INTER_REF={0} ', inputs.inter_version_ref) || ''}}${{ + inputs.target_version_ref != '' && format(' -DYDB_COMPAT_TARGET_REF={0}', inputs.target_version_ref) || ''}} diff --git a/ydb/tests/compatibility/README.md b/ydb/tests/compatibility/README.md index cdae5d76fdf..d92fa615724 100644 --- a/ydb/tests/compatibility/README.md +++ b/ydb/tests/compatibility/README.md @@ -4,7 +4,7 @@ ## Механика работы тестов -Тестовая обвязка скачивает YDB последней стабильной версии. После этого тестам доступны два бинарных файла: текущий (собранный из текущего среза исходников) и предыдущий. Таким образом, в этих тестах можно использовать тестовый кластер не только с одной версией YDB, но и с двумя. Текущая версия условно называется **current**, а предыдущая — **last**. +Тестовая обвязка скачивает YDB последней стабильной версии. После этого тестам доступны два бинарных файла: текущий (собранный из текущего среза исходников) и предыдущий. Таким образом, в этих тестах можно использовать тестовый кластер не только с одной версией YDB, но и с двумя. Текущая версия условно называется **current/target**, а предыдущая — **initial**. ## Как написать тест @@ -20,14 +20,14 @@ ### MixedClusterFixture -Фикстура поднимает кластер, который состоит из нод версий current и last. Позволяет протестировать работу в режиме, когда часть нод у нас уже обновилась, а часть еще нет. +Фикстура поднимает кластер, который состоит из нод версий current и init. Позволяет протестировать работу в режиме, когда часть нод у нас уже обновилась, а часть еще нет. Имеет параметризацию (то есть каждый написанный такой тест превращается в несколько): -- поднимается смешанный кластер last+current -- поднимается кластер исключительно на версии last +- поднимается смешанный кластер init+current +- поднимается кластер исключительно на версии init - поднимается кластер исключительно на версии current -Последние два нужны, чтобы отвечать на вопрос "а работает ли такой сценарий в принципе, когда кластер состоит из нод одной версии". Если получается так, что тест last+current не проходит, а в отсутствие разных версий тест завершается успешно, то это сильный сигнал к тому, что где-то поломана совместимость. +Последние два нужны, чтобы отвечать на вопрос "а работает ли такой сценарий в принципе, когда кластер состоит из нод одной версии". Если получается так, что тест init+current не проходит, а в отсутствие разных версий тест завершается успешно, то это сильный сигнал к тому, что где-то поломана совместимость. #### Для чего использовать @@ -35,11 +35,11 @@ ### RestartToAnotherVersionFixture -Фикстура сначала поднимает кластер в одной комбинации (например, все ноды last), а потом позволяет остановить кластер и поднять кластер с другими версиями (например, все ноды current). +Фикстура сначала поднимает кластер в одной комбинации (например, все ноды init), а потом позволяет остановить кластер и поднять кластер с другими версиями (например, все ноды current). Имеет параметризацию (то есть каждый написанный такой тест превращается в несколько): -- обновление last → current -- обновление current → last +- обновление init → current +- обновление current → init - обновление current → current Список не исчерпывающий, полный можно посмотреть в коде фикстуры. @@ -52,9 +52,9 @@ ### RollingUpgradeAndDowngradeFixture -Фикстура позволяет протестировать сценарий роллинг-апгрейда и даунгрейда. Реализует сценарий "имеется кластер last версии, он понодно заменяется на current версию, потом обратно на last". +Фикстура позволяет протестировать сценарий роллинг-апгрейда и даунгрейда. Реализует сценарий "имеется кластер init версии, он понодно заменяется на current версию, потом обратно на init". -Сама фикстура сначала поднимает кластер версии last, потом заменяет ноды на версию current, а потом обратно понодно заменяет на last, эмулируя откат. +Сама фикстура сначала поднимает кластер версии init, потом заменяет ноды на версию current, а потом обратно понодно заменяет на init, эмулируя откат. Шаг апгрейда/даунгрейда (замена версии ноды на другую) вызывается из теста следующим образом: @@ -65,20 +65,20 @@ for _ in self.roll(): На каждой итерации цикла тестовое окружение заменяет одну ноду на другую версию. -Схематично можно изобразить следующим образом (L — last, C — current, каждый столбец — это версия ноды кластера, каждая строка — текущее состояние кластера в теле цикла): +Схематично можно изобразить следующим образом (I — init, C — current, каждый столбец — это версия ноды кластера, каждая строка — текущее состояние кластера в теле цикла): ``` -LLLLLLLLL -CLLLLLLLL -CCLLLLLLL +IIIIIIIII +CIIIIIIII +CCIIIIIII ... -CCCCCCCCL +CCCCCCCCI CCCCCCCCC -LCCCCCCCC -LLCCCCCCC +ICCCCCCCC +IICCCCCCC ... -LLLLLLLLC -LLLLLLLLL +IIIIIIIIC +IIIIIIIII ``` #### Для чего использовать diff --git a/ydb/tests/compatibility/ya.make b/ydb/tests/compatibility/ya.make index 537e2359c96..1f3a7ab7db7 100644 --- a/ydb/tests/compatibility/ya.make +++ b/ydb/tests/compatibility/ya.make @@ -29,9 +29,10 @@ REQUIREMENTS(ram:all) INCLUDE(${ARCADIA_ROOT}/ydb/tests/large.inc) INCLUDE(${ARCADIA_ROOT}/ydb/tests/tools/s3_recipe/recipe.inc) + DEPENDS( - ydb/apps/ydb ydb/tests/library/compatibility/binaries + ydb/apps/ydb ) PEERDIR( diff --git a/ydb/tests/library/compatibility/binaries/downloader/__main__.py b/ydb/tests/library/compatibility/binaries/downloader/__main__.py index f1df08a3217..f5b893b4043 100644 --- a/ydb/tests/library/compatibility/binaries/downloader/__main__.py +++ b/ydb/tests/library/compatibility/binaries/downloader/__main__.py @@ -11,24 +11,30 @@ AWS_BUCKET = "ydb-builds" def main(): - s3_client = boto3.client( - service_name="s3", - endpoint_url=AWS_ENDPOINT, - config=Config(signature_version=UNSIGNED) - ) + mode = sys.argv[1] + if mode == 'download': + s3_client = boto3.client( + service_name="s3", + endpoint_url=AWS_ENDPOINT, + config=Config(signature_version=UNSIGNED) + ) + s3_bucket = AWS_BUCKET + remote_src = sys.argv[2] + local_dst = sys.argv[3] + binary_name = sys.argv[4] + s3_client.download_file(s3_bucket, remote_src, local_dst) - s3_bucket = AWS_BUCKET - remote_src = sys.argv[1] - local_dst = sys.argv[2] - binary_name = sys.argv[3] - s3_client.download_file(s3_bucket, remote_src, local_dst) + # chmod +x + st = os.stat(local_dst) + os.chmod(local_dst, st.st_mode | stat.S_IEXEC) - # chmod +x - st = os.stat(local_dst) - os.chmod(local_dst, st.st_mode | stat.S_IEXEC) - - with open(local_dst + "-name", "w") as f: - f.write(binary_name) + with open(local_dst + "-name", "w") as f: + f.write(binary_name) + elif mode == 'append-version': + local_dst = sys.argv[2] + binary_name = sys.argv[3] + with open(local_dst, "w") as f: + f.write(binary_name) if __name__ == "__main__": diff --git a/ydb/tests/library/compatibility/binaries/ya.make b/ydb/tests/library/compatibility/binaries/ya.make index 2d4e6c96eb1..4d64a24111c 100644 --- a/ydb/tests/library/compatibility/binaries/ya.make +++ b/ydb/tests/library/compatibility/binaries/ya.make @@ -2,14 +2,40 @@ RECURSE(downloader) UNION() +IF(NOT ${YDB_COMPAT_INIT_REF}) + SET(YDB_COMPAT_INIT_REF stable-24-4) +ENDIF() +IF(NOT ${YDB_COMPAT_INTER_REF}) + SET(YDB_COMPAT_INTER_REF stable-25-1-2) +ENDIF() +IF(NOT ${YDB_COMPAT_TARGET_REF}) + SET(YDB_COMPAT_TARGET_REF current) +ENDIF() + RUN_PROGRAM( - ydb/tests/library/compatibility/binaries/downloader stable-25-1/release/ydbd ydbd-last-stable 25-1 - OUT_NOAUTO ydbd-last-stable ydbd-last-stable-name + ydb/tests/library/compatibility/binaries/downloader download $YDB_COMPAT_INTER_REF/release/ydbd ydbd-inter $YDB_COMPAT_INTER_REF + OUT_NOAUTO ydbd-inter ydbd-inter-name ) RUN_PROGRAM( - ydb/tests/library/compatibility/binaries/downloader stable-24-4/release/ydbd ydbd-prelast-stable 24-4 - OUT_NOAUTO ydbd-prelast-stable ydbd-prelast-stable-name + ydb/tests/library/compatibility/binaries/downloader download $YDB_COMPAT_INIT_REF/release/ydbd ydbd-init $YDB_COMPAT_INIT_REF + OUT_NOAUTO ydbd-init ydbd-init-name ) +IF(${YDB_COMPAT_TARGET_REF} != "current") + RUN_PROGRAM( + ydb/tests/library/compatibility/binaries/downloader download $YDB_COMPAT_TARGET_REF/release/ydbd ydbd-target $YDB_COMPAT_TARGET_REF + OUT_NOAUTO ydbd-target ydbd-target-name + ) +ELSE() + INCLUDE(${ARCADIA_ROOT}/ydb/tests/ydbd_dep.inc) + BUNDLE( + ydb/apps/ydbd NAME ydbd-target + ) + RUN_PROGRAM( + ydb/tests/library/compatibility/binaries/downloader append-version ydbd-target-name current + OUT_NOAUTO ydbd-target-name + ) +ENDIF() + END() diff --git a/ydb/tests/library/compatibility/fixtures.py b/ydb/tests/library/compatibility/fixtures.py index 0f2d9698f6e..dc15570d7c5 100644 --- a/ydb/tests/library/compatibility/fixtures.py +++ b/ydb/tests/library/compatibility/fixtures.py @@ -5,23 +5,17 @@ import yatest import time from ydb.tests.library.harness.kikimr_runner import KiKiMR from ydb.tests.library.harness.kikimr_config import KikimrConfigGenerator -from ydb.tests.library.harness.param_constants import kikimr_driver_path from ydb.tests.library.common.types import Erasure from ydb.tests.oss.ydb_sdk_import import ydb -current_binary_path = kikimr_driver_path() -last_stable_binary_path = yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-last-stable") -prelast_stable_binary_path = yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-prelast-stable") - -current_binary_version = (float("+inf"), ) -last_stable_version = None -prelast_stable_version = None - - def string_version_to_tuple(s): result = [] - for elem in s.split("-"): + s = s.replace('.', '-') + for idx, elem in enumerate(s.split("-")): + # skipping 'stable' in stable-25-1-1 version + if idx == 0 and elem == 'stable': + continue try: result.append(int(elem)) except ValueError: @@ -29,39 +23,53 @@ def string_version_to_tuple(s): return tuple(result) -current_name = "current" -last_stable_name = "last" -if last_stable_binary_path is not None: # in import_test yatest.common.binary_path returns None - last_stable_name = open(yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-last-stable-name")).read().strip() - last_stable_version = string_version_to_tuple(last_stable_name) -prelast_stable_name = "prelast" -if prelast_stable_binary_path: # in import_test yatest.common.binary_path returns None - prelast_stable_name = open(yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-prelast-stable-name")).read().strip() - prelast_stable_version = string_version_to_tuple(prelast_stable_name) +current_binary_path = yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-target") +current_name = 'current' +if current_binary_path is not None: + with open(yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-target-name")) as f: + current_name = f.read().strip() +current_binary_version = string_version_to_tuple(current_name) + +inter_stable_binary_path = yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-inter") +init_stable_binary_path = yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-init") + +inter_stable_version = None +init_stable_version = None + +inter_stable_name = "intermediate" +if inter_stable_binary_path is not None: # in import_test yatest.common.binary_path returns None + with open(yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-inter-name")) as f: + inter_stable_name = f.read().strip() + inter_stable_version = string_version_to_tuple(inter_stable_name) +init_stable_name = "initial" +if init_stable_binary_path: # in import_test yatest.common.binary_path returns None + with open(yatest.common.binary_path("ydb/tests/library/compatibility/binaries/ydbd-init-name")) as f: + init_stable_name = f.read().strip() + init_stable_version = string_version_to_tuple(init_stable_name) path_to_version = { current_binary_path: current_binary_version, - last_stable_binary_path: last_stable_version, - prelast_stable_binary_path: prelast_stable_version, + inter_stable_binary_path: inter_stable_version, + init_stable_binary_path: init_stable_version, } all_binary_combinations_restart = [ - [[last_stable_binary_path], [current_binary_path]], - [[current_binary_path], [last_stable_binary_path]], + [[inter_stable_binary_path], [current_binary_path]], + [[current_binary_path], [inter_stable_binary_path]], [[current_binary_path], [current_binary_path]], - [[prelast_stable_binary_path], [last_stable_binary_path]], - [[last_stable_binary_path], [prelast_stable_binary_path]], - [[last_stable_binary_path], [last_stable_binary_path]], + [[init_stable_binary_path], [inter_stable_binary_path]], + [[inter_stable_binary_path], [init_stable_binary_path]], + [[inter_stable_binary_path], [inter_stable_binary_path]], ] all_binary_combinations_ids_restart = [ - "restart_{}_to_{}".format(last_stable_name, current_name), - "restart_{}_to_{}".format(current_name, last_stable_name), + "restart_{}_to_{}".format(inter_stable_name, current_name), + "restart_{}_to_{}".format(current_name, inter_stable_name), "restart_{}_to_{}".format(current_name, current_name), - "restart_{}_to_{}".format(prelast_stable_name, last_stable_name), - "restart_{}_to_{}".format(last_stable_name, prelast_stable_name), - "restart_{}_to_{}".format(last_stable_name, last_stable_name), + "restart_{}_to_{}".format(init_stable_name, inter_stable_name), + "restart_{}_to_{}".format(inter_stable_name, init_stable_name), + "restart_{}_to_{}".format(inter_stable_name, inter_stable_name), ] @@ -118,15 +126,15 @@ class RestartToAnotherVersionFixture: all_binary_combinations_mixed = [ [current_binary_path], - [last_stable_binary_path], - [current_binary_path, last_stable_binary_path], - [last_stable_binary_path, prelast_stable_binary_path], + [inter_stable_binary_path], + [current_binary_path, inter_stable_binary_path], + [inter_stable_binary_path, init_stable_binary_path], ] all_binary_combinations_ids_mixed = [ "mixed_{}".format(current_name), - "mixed_{}".format(last_stable_name), - "mixed_{}".format(current_name + "_and_" + last_stable_name), - "mixed_{}".format(last_stable_name + "_and_" + prelast_stable_name), + "mixed_{}".format(inter_stable_name), + "mixed_{}".format(current_name + "_and_" + inter_stable_name), + "mixed_{}".format(inter_stable_name + "_and_" + init_stable_name), ] @@ -159,12 +167,12 @@ class MixedClusterFixture: all_binary_combinations_rolling = [ - [last_stable_binary_path, current_binary_path], - [prelast_stable_binary_path, last_stable_binary_path], + [inter_stable_binary_path, current_binary_path], + [init_stable_binary_path, inter_stable_binary_path], ] all_binary_combinations_ids_rolling = [ - "rolling_{}_to_{}".format(last_stable_name, current_name), - "rolling_{}_to_{}".format(prelast_stable_name, last_stable_name), + "rolling_{}_to_{}".format(inter_stable_name, current_name), + "rolling_{}_to_{}".format(init_stable_name, inter_stable_name), ] |
