Привет! Меня зовут Артем, я QA full-stack в команде TData. Мы занимаемся разработкой высоконагруженных корпоративных решений. Для нас автоматизация тестирования - это не просто способ снять нагрузку с ручных тестировщиков, а важная часть инженерной культуры.

UI + API как единый интеграционный контур: опыт RT.ClusterManager и RT.WareHouse

Вместо разрозненных UI- и API-тестов мы построили единый контур: UI создает сущности, API проверяет их через RestAssured, а SSH подтверждает состояние на хостах.
Один сценарий - три уровня проверки.

В этом примере я расскажу о реализации на базе RT.ClusterManager (СМ) - системы управления кластерами и их конфигурацией - RT.Warehouse (WH), который через СМ поднимает и обслуживает кластеры хранилища данных на реальных серверах.

Почему раздельные тесты больше не работают

В типичном проекте тесты функционируют обособленно:

  • UI-тесты проверяют логин, клики, видимость элементов. Создают кластер через форму, но не убеждаются, что он реально появился в API.

  • API-тесты проверяют статусы и тело ответа, но работают с «чистыми» данными, созданными напрямую через API, без участия UI.

  • Инфраструктура проверяется вручную по SSH: Wal-G и конфиги видны в UI, но не подтверждаются на уровне ОС.

В результате:

  • UI создал кластер, но API-тест не знает его ID и имя - приходится хардкодить или использовать моки.

  • API подтверждает, что «что-то» существует, но нет гарантии, что это создано через UI.

  • Настройки провайдера и Wal-G видны в интерфейсе, но не проверяются на реальных хостах.

С этой проблемой мы столкнулись в RT.ClusterManager: нужно было проверять не только кнопки и API-ответы, а весь путь - от действий пользователя в UI до фактического состояния инфраструктуры.

Идея: единый интеграционный контур

Мы объединили три уровня в одном сценарии:

  1. UI (Selenide): создаем провайдеры, кластеры, настраиваем плагины, добавляем хосты.

  2. API (RestAssured): проверяем те же сущности через REST - списки, поля, статусы.

  3. SSH: выполняем команды на хостах и проверяем реальное состояние - процессы, конфиги, логи.

Данные создаются в UI, переиспользуются в API и подтверждаются на уровне ОС.
Один набор констант - для всех уровней.

Как это выглядит на практике: RT.WareHouse + Wal-G

1) Подготовка (@BeforeAll / @BeforeEach)

@BeforeAll
public static void setupOnce() {
    rtSystemPlugin = downloadPlugin("rt.system:RT.System-1.6.0");
    wareHousePlugin = downloadPlugin("rt.warehouse:RT.WareHouse-2.13.10");
}

@BeforeEach
public void setup() {
    Selenide.open("/login");
    loginPage.authorization(LOGIN_USERNAME, LOGIN_PASSWORD);
    barPage.avatarShouldExist();
}

2) UI: создание провайдера и кластера

InfrastructureManager.addPluginWh(rtSystemPlugin);
InfrastructureManager.addPluginWh(wareHousePlugin);

InfrastructureManager.createProviderWithHostsWh(
    PROVIDER_NAME_WH_INTEGRATION1,
    PROVIDER_DESCRIPTION_INTEGRATION
);

InfrastructureManager.validateHostsWh();

InfrastructureManager.createClusterWhWithPluginVersion(
    wareHousePlugin,
    CLUSTER_NAME_WH_INTEGRATION,
    CLUSTER_DESCRIPTION_INTEGRATION
);

InfrastructureManager.setUpConfigInClusterForPluginsWhOnRedos();
InfrastructureManager.setUpWalgBackupConfGp();
InfrastructureManager.addHostAndInstallGp();

3) Терминал: настройка NFS и проверка на хостах

infrastructureManager.executeCmTerminalCommands();          // NFS на CM
infrastructureManager.executeM1AndS1TerminalCommands();     // NFS на M1, S1
infrastructureManager.verifyAllTerminalCommandsResults();   // проверка скриптов, /backup

4) UI: финальная проверка (Run Wal-G)

InfrastructureManager.clickOnRunWalgAndCheckVisibleSuccessfulRunWalg();

Технический стек

  • UI: Selenide, Page Object

  • API: RestAssured, TokenManager

  • Терминал: JSch, RemoteCommandExecutor

  • Сборка/отчеты: Gradle, Allure

  • Общие данные: единые константы (имена, URL, креды, хосты)

API-слой в этом контуре

API-тесты остаются в отдельных классах, но работают с теми же данными. Пример:

@BeforeEach
public void auth() {
    Response response = TokenManager.getToken(
        ApiConfig.getDefaultUsername(),
        ApiConfig.getDefaultPassword()
    );
    this.token = TokenManager.extractToken(response);
}

Response response = given()
    .header("Authorization", "Bearer " + token)
    .contentType(ContentType.JSON)
.when()
    .get("/cluster")
.then()
    .statusCode(200)
    .extract().response();

В интеграционном сценарии после создания кластера через UI добавляется API-проверка полей и статусов. Это подтверждает, что UI и API работают с одной и той же сущностью.

Плюсы подхода

  • Ловим ошибки на стыке UI, API и инфраструктуры.

  • Снижаем дублирование: один набор данных на все уровни.

  • Ближе к реальным пользовательским сценариям.

  • Быстрее локализуем причину падения:

  • UI создал, API не видит → проблема API/БД.

  • API видит, а на хосте пусто → проблема деплоя/конфигов.

Минусы и сложности

  • Интеграционный тест может идти 20–30 минут.

  • Сильная зависимость от стенда: ВМ, сеть, SSH.

  • Сложная конфигурация (хосты, URL, креды, переменные окружения).

Рекомендации

  1. Выносите общие данные в константы, не хардкодьте в тестах.

  2. Разделяйте быстрые и долгие сценарии.

  3. Используйте единый источник правды для хостов и URL (конфиги + env).

  4. Логируйте шаги и собирайте Allure-отчеты.

Как эта статья продолжает предыдущие

Эта статья логично опирается на две предыдущие:

Здесь следующий шаг: к UI и интеграционным тестам добавляются API и SSH, чтобы получить сквозной контур проверки.

Вывод

Контур UI → API → SSH дает целостную картину работы системы.
На примере CM/WH такой подход позволяет проверять не только интерфейс, но и фактическое состояние инфраструктуры после действий в UI.
Единый набор данных и общая конфигурация упрощают поддержку, а связка UI+API+SSH естественно развивает подходы, описанные в предыдущих статьях.