Тестирование сопоставления

В этой статье приводится краткое описание сопоставления тестов и объясняется, как начать настраивать тесты в Android Open Source Project (AOSP).

О сопоставлении тестов

Сопоставление тестов – это подход на основе Gerrit, который позволяет разработчикам создавать правила тестирования до и после отправки непосредственно в дереве исходного кода Android и оставлять решения о ветвях и устройствах, которые будут тестироваться, инфраструктуре тестирования. Определения сопоставления тестов – это JSON-файлы с названием TEST_MAPPING, которые можно разместить в любом каталоге с исходными файлами.

Atest может использовать файлы TEST_MAPPING для запуска тестов перед отправкой в связанных каталогах. С помощью сопоставления тестов вы можете добавить тот же набор тестов в предварительные проверки, внеся минимальные изменения в дерево исходного кода Android.

Примеры:

Для тестирования сопоставления используется тестовая платформа Trade Federation (TF), которая позволяет выполнять тесты и создавать отчеты о результатах.

Определите тестовые группы

Проверьте сопоставление групп с помощью тестовой группы. Название тестовой группы может быть любой строкой. Например, presubmit может быть названием группы тестов, которые выполняются при проверке изменений. А postsubmit – это тесты, которые используются для проверки сборок после объединения изменений.

Правила скрипта сборки пакета

Чтобы тестовая программа Trade Federation могла запускать тестовые модули для определенной сборки, для этих модулей должно быть задано значение test_suites для Soong или LOCAL_COMPATIBILITY_SUITE для Make в одном из следующих наборов:

  • general-tests – для тестов, которые не зависят от возможностей конкретного устройства (например, от аппаратного обеспечения определенного поставщика, которого нет на большинстве устройств). Большинство тестов должны быть в наборе general-tests, даже если они относятся к определенному ABI, разрядности или аппаратным функциям, таким как HWASan (для каждого ABI есть отдельная цель test_suites), и даже если их нужно запускать на устройстве.
  • device-tests – для тестирования функций, которые зависят от возможностей устройства. Обычно эти тесты находятся в разделе vendor/. Device-specific относится только к возможностям, уникальным для определенного устройства, поэтому это относится к тестам JUnit, а также к тестам GTest (которые обычно должны быть помечены как general-tests, даже если они зависят от ABI).

Примеры:

Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests

Как настроить запуск тестов в наборе тестов

Чтобы тест можно было запустить в наборе тестов, он должен:

  • Не должен иметь поставщика сборки.
  • После завершения работы должен удалять временные файлы, созданные во время тестирования.
  • Необходимо изменить системные настройки на значения по умолчанию или исходные значения.
  • Не следует предполагать, что устройство находится в определенном состоянии, например готово к получению root-доступа. Для большинства тестов не требуются права root. Если для теста требуются права root, это нужно указать с помощью параметра RootTargetPreparer в элементе AndroidTest.xml, как показано в следующем примере:

    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    

Как создать тестовые файлы сопоставления

Для каталога, требующего покрытия тестами, добавьте файл JSON TEST_MAPPING, похожий на пример. Эти правила гарантируют, что тесты будут выполняться при предварительных проверках, когда затрагиваются какие-либо файлы в этом каталоге или любом из его подкаталогов.

Пример

Ниже приведен пример файла TEST_MAPPING (в формате JSON, но с поддержкой комментариев).

{
  "presubmit": [
    // JUnit test with options and file patterns.
    {
      "name": "CtsWindowManagerDeviceTestCases",
      "options": [
        {
          "include-annotation": "android.platform.test.annotations.RequiresDevice"
        }
      ],
      "file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
    },
    // Device-side GTest with options.
    {
      "name" : "hello_world_test",
      "options": [
        {
          "native-test-flag": "\"servicename1 servicename2\""
        },
        {
          "native-test-timeout": "6000"
        }
      ]
    }
    // Host-side GTest.
    {
      "name" : "net_test_avrcp",
      "host" : true
    }
  ],
  "postsubmit": [
    {
      "name": "CtsDeqpTestCases",
      "options": [
        {
          // Use regex in include-filter which is supported in AndroidJUnitTest
          "include-filter": "dEQP-EGL.functional.color_clears.*"
        }
      ]
    }
  ],
  "imports": [
    {
      "path": "frameworks/base/services/core/java/com/android/server/am"
    }
  ]
}

Как задать атрибуты

В примере presubmit и postsubmit – это названия каждой тестовой группы. Подробнее об определении тестовых групп…

Вы можете задать название тестового модуля или интеграционного теста Trade Federation (путь к XML-файлу теста, например uiautomator/uiautomator-demo) в значении атрибута name. Обратите внимание, что в поле name нельзя использовать класс name или тестовый метод name. Чтобы выбрать, какие тесты нужно запустить, используйте такие параметры, как include-filter. Пример использования include-filter.

Параметр host в тесте указывает, является ли тест без устройства и выполняется ли он на хосте. Значение по умолчанию – false, то есть для выполнения теста требуется устройство. Поддерживаемые типы тестов: HostGTest для двоичных файлов GTest и HostTest для тестов JUnit.

Атрибут file_patterns позволяет задать список строк регулярных выражений для сопоставления относительного пути любого файла исходного кода (относительно каталога, содержащего файл TEST_MAPPING). В примере тест CtsWindowManagerDeviceTestCases выполняется в предкоммите только в том случае, если файл Java начинается с Window или Activity и находится в том же каталоге, что и файл TEST_MAPPING, или в одном из его подкаталогов. Обратные косые черты (\) нужно экранировать, поскольку они находятся в файле JSON.

Импорт файлов TEST_MAPPING

Атрибут imports позволяет включать тесты в другие файлы TEST_MAPPING без копирования контента. Также будут включены файлы TEST_MAPPING в родительских каталогах импортированного пути. TEST_MAPPING позволяет выполнять вложенный импорт, то есть импортированные файлы могут импортировать другие файлы TEST_MAPPING, а при сопоставлении тестов включенные тесты могут объединяться.

TEST_MAPPING поддерживает импорт на уровне корневого каталога и группы:

  • Импорт на корневом уровне. Указывается на верхнем уровне файла TEST_MAPPING (вне тестовых групп). При импорте на корневом уровне целевой файл TEST_MAPPING (и его родительские каталоги) импортируется полностью, как если бы он был записан в пути, в который он импортируется. Все определения тестовых групп в импортированном файле (например, presubmit, postsubmit) объединяются с соответствующими тестовыми группами в импортируемом файле.
  • Импорт на уровне группы. Указывается непосредственно в определенной тестовой группе (например, presubmit или postsubmit). Импорт на уровне группы строго ограничен этой тестовой группой, то есть будут импортированы только тесты, определенные в этой группе в целевом файле TEST_MAPPING. Все остальные тестовые группы в целевом файле игнорируются.

Импорт на уровне группы позволяет точно контролировать выполнение тестов. Например, вы можете импортировать тесты, предназначенные для предварительной отправки, не добавляя ресурсоемкие тесты для последующей отправки из импортированного каталога.

Пример импорта на корневом уровне:

{
  "imports": [
    {
      "path": "frameworks/base/services/core"
    }
  ],
  "presubmit": [
    {
      "name": "MyTestModule"
    }
  ]
}

Пример импорта на уровне группы:

{
  "presubmit": [
    {
      "name": "MyTestModule"
    },
    {
      "imports": [
        {
          "path": "frameworks/base/services/core"
        }
      ]
    }
  ],
  "postsubmit": [
    {
      "imports": [
        {
          "path": "frameworks/base/services/accessibility"
        }
      ]
    }
  ]
}

Атрибут options содержит дополнительные параметры командной строки Tradefed.

Чтобы получить полный список доступных вариантов для определенного теста, выполните следующую команду:

tradefed.sh run commandAndExit [test_module] --help

Подробную информацию о том, как работают параметры, можно найти в статье Обработка параметров в Tradefed.

Проверки TEST_MAPPING

При отправке изменений, которые вносят правки в файлы TEST_MAPPING, выполняются предварительные проверки, чтобы убедиться в их корректности:

  • Проверка шаблонов файлов. Убедитесь, что все регулярные выражения в файле file_patterns соответствуют хотя бы одному файлу в репозитории. Устаревшие шаблоны, не соответствующие ни одному файлу, приводят к сбою проверки.
  • Проверка во время сборки. Предупреждения, собранные во время сборки, будут преобразованы в блокирующие ошибки при предварительной отправке для основных веток. Распространенные предупреждения:
    • Несуществующие модули. Ссылка на название тестового модуля, которого нет в базе кода, например из-за опечатки.
    • Недействительные импортированные файлы. Пути к цифровым отпечаткам в файле imports, которые не существуют или не содержат файл TEST_MAPPING.
    • Проблемы со схемой. В конфигурации JSON используются неподдерживаемые ключи или неправильно сформированные структуры.

Как запустить тесты с помощью Atest

Чтобы выполнить правила тестирования перед отправкой локально:

  1. Перейдите в каталог, содержащий файл TEST_MAPPING.
  2. Выполните команду:

    atest
    

Выполняются все тесты, настроенные в файлах TEST_MAPPING текущего каталога и его родительских каталогов. Atest находит и запускает два теста для предварительной отправки (A и B).

Это самый простой способ запустить тесты перед отправкой в файлах TEST_MAPPING в текущем рабочем каталоге и родительских каталогах. Atest находит и использует файл TEST_MAPPING в CWD и всех его родительских каталогах.

Исходный код структуры

В этом примере показано, как настроить файлы TEST_MAPPING в дереве исходного кода:

src
├── project_1
│   └── TEST_MAPPING
├── project_2
│   └── TEST_MAPPING
└── TEST_MAPPING

Контент src/TEST_MAPPING:

{
  "presubmit": [
    {
      "name": "A"
    }
  ]
}

Содержимое файла src/project_1/TEST_MAPPING:

{
  "presubmit": [
    {
      "name": "B"
    }
  ],
  "postsubmit": [
    {
      "name": "C"
    }
  ],
  "other_group": [
    {
      "name": "X"
    }
  ]}

Содержимое файла src/project_2/TEST_MAPPING:

{
  "presubmit": [
    {
      "name": "D"
    }
  ],
  "import": [
    {
      "path": "src/project_1"
    }
  ]}

Укажите целевые каталоги

Вы можете указать целевой каталог, чтобы запустить тесты в файлах TEST_MAPPING в этом каталоге. Следующая команда запускает два теста (A и B):

atest --test-mapping src/project_1

Как запустить правила тестирования после отправки

Эту команду также можно использовать для запуска правил тестирования после отправки, определенных в файле TEST_MAPPING в каталоге src_path (по умолчанию используется текущий рабочий каталог) и его родительских каталогах:

atest [--test-mapping] [src_path]:postsubmit

Запускать только тесты, для которых не требуется устройство

Вы можете использовать параметр --host для Atest, чтобы запускать только те тесты, которые настроены для хоста и не требуют устройства. Без этого параметра Atest запускает оба типа тестов: те, которые требуют устройство, и те, которые выполняются на хосте без устройства. Тесты выполняются в двух отдельных наборах:

atest [--test-mapping] --host

Определите тестовые группы

Вы можете указать тестовые группы в команде Atest. Следующая команда запускает все тесты postsubmit, связанные с файлами в каталоге src/project_1, который содержит только один тест (C).

Или вы можете использовать :all, чтобы запустить все тесты независимо от группы. Следующая команда запускает четыре теста (A, B, C, X):

atest --test-mapping src/project_1:all

Включить подкаталоги

По умолчанию при запуске тестов в TEST_MAPPING с помощью Atest выполняются только тесты, которые настроены в файле TEST_MAPPING в текущем рабочем каталоге (или указанном каталоге) и его родительских каталогах. Если вы хотите запустить тесты во всех файлах TEST_MAPPING в подкаталогах, используйте параметр --include-subdir, чтобы принудительно включить эти тесты в Atest.

atest --include-subdir

Без параметра --include-subdir Atest выполняет только тест A. При использовании параметра --include-subdir Atest выполняет два теста (A и B).

Поддерживаются комментарии на уровне строк

Вы можете добавить комментарий в формате // на уровне строки, чтобы дополнить файл TEST_MAPPING описанием настройки, которая следует за ним. ATest и Trade Federation предварительно обрабатывают TEST_MAPPING в действительный формат JSON без комментариев. Чтобы JSON-файл был понятным, поддерживается только комментарий в формате // на уровне строки.

Пример:

{
  // For presubmit test group.
  "presubmit": [
    {
      // Run test on module A.
      "name": "A"
    }
  ]
}