Как Eolymp тестирует решения
Сегодня мы разберемся с тем, как Eolymp тестирует и оценивает решения: что происходит после того, как вы отправляете решение,как он запускается, как происходит проверка результатов и какие они бывают. Надеюсь, эта статья поможет вам лучшепонять, как работает система и упростит работу с ней.
Мы также рассмотрим, как работают некоторые новые функции на сайте, а именно наборы тестов и интерактивные задачи.
Для начала стоит отметить, что сайт и тестирующая система это две отдельные программы. Сайт позволяет пользователям отправлятьрешения и просматривать результаты, а тестирующая система запускает и оценивает их. Такое распределение позволяет упростить каждую изпрограмм и разделить обязанности между ними.
Когда вы нажимаете кнопку "Отправить" на сайте, ваше решение сохраняется в очередь тестирования, откуда его получает тестирующая система и начинает тестирование.
Очередь тестирования
Очередь это такой дополнительный буфер между сайтом и тестирующей системой.Благодаря ему, даже если тестирующая система не успевает обрабатывать все решения, сайт все равно может продолжать работать и принимать новые решения. Очередь будет хранить их, пока одна из тестирующих систем не освободится.
На Eolymp постоянно работают несколько тестирующих систем, которые постоянно проверяют очередь и получают решения для тестирования.
Каждая тестирующая система имеет отдельный выделенный сервер и в каждый момент времени проверяет только одно решение.Решения никогда не проверяются параллельно на одном и том же сервере, так как это может повлиять на результат проверки.
Обычно решения не задерживаются в очереди на долго, но иногда они могут храниться в очереди определенное время.Когда решений много, они начинают накапливаться в очереди и вы можете видеть, что ваше решение остается в статусе "Ожидает" определенное время.
Подготовка и компиляция
Когда тестирующая система получает решение из очереди, начинается процедура подготовки и компиляции.На этом этапе тестирующая система готовит все необходимое для запуска и дальнейшего тестирования.
Прежде всего, тестирующая система создает пустую рабочую папку и новую изолированную среду, где будет запускаться ваша программа.Далее, система создает файл с исходным кодом программы и запускает команду компиляции.Например, для C++ система создаст файл source.cpp
и выполнит команду g++ source.cpp -o a.exe
.
Если команда компиляции исполнится с ошибкой, система засчитывает результат "Ошибка компиляции". В таком случае вывод команды компиляции отправляется на сайт для того, чтобы вы могли увидеть текст ошибки. В этом случае тестирующая система завершит процесс на этом этапе.
В зависимости от языка программирования команда компиляции будет отличаться. Для языков программирования, которые требуют компиляции в машинный код (или байт-код), команда компиляции создаст соответствующий бинарный файл.Для языков программирования, которые не требуют компиляции, команда компиляции не выполняется или просто выполняет простую проверку на синтаксические ошибки, например, если вы забыли поставить ";".
Если файл с исходным кодом не нужен для запуска, он удаляется.
Если компиляция завершилась успешно, система переходит к запуску вашей программы.
Запуск и проверка результата
Сначала в рабочую папку копируется файл с входными данными input.txt
, а затем выполняется команда запуска.
Подобно команде компиляции, команда запуска отличается для различных языков программирования.Например, для C++, командой запуска есть имя бинарного файла a.exe
, а для PHP команда выполнения выглядит так php source.php
.
При запуске тестирующая система направляет содержание файла input.txt
в стандартный поток ввода программы (stdin), а стандартный поток вывода (stdout) направляется в файл output.txt
. Это означает, что вместо ввода с клавиатуры, ваша программа будет считывать данные из файла input.txt
, а все, что напечатает ваша программа будет автоматически сохранено в файл output.txt
.
Это аналогично тому, когда вы запускаете команду через командную строку вот так: a.exe < input.txt output.txt
.
Тестирующая система начинает следить за процессом программы в ожидании его завершения. В момент запуска программы, тестирующая система запускает таймер времени выполнения.Когда этот таймер превышает максимальный разрешенный лимит (лимит на время выполнения программы), тестирующая система останавливает процесс специальным сигналом к операционной системе.
После завершения, тестирующая система получает данные об использовании ресурсов программой-решением. Эти данные включают код завершения (exit code), объем памяти и время использования процессора.
Следующим шагом запускается процесс проверки результата.
Прежде всего, проверяется время выполнения программы. Система сравнивает время выполнения с лимитом и если он превышен, тестирующая система засчитывает результат "Исчерпан лимит времени".
Следующим проверяется лимит использования памяти. Если объем памяти превышает допустимый лимит, тестирующая система засчитывает результат "Исчерпан лимит памяти".
Далее проверяется код завершения (exit code). По стандарту, код завершения программы должен быть 0 в случае успешного выполнения, и отличный от 0 в случае ошибки.Например, если ваша программа попытается получить доступ к не корректной области памяти, операционная система прекратит выполнение вашей программы с не нулевым кодом завершения.
Таким образом, если ваша программа вернет не нулевой код завершения, тестирующая система засчитает результат "Ошибка выполнения" и перейдет к запуску следующего теста.
Если же код завершения - нулевой, начнется процедура сравнения ответа.
На этом этапе система копирует файл с правильным ответом answer.txt
в рабочую папку и сравнивает его с ответом output.txt
.
В зависимости от задачи, ответ может проверяться по разному. К каждой задаче закреплена специальная программа, которая выполняет сравнение. Эта программа называется "чекер".
Во многих задачах ответ сравнивается посимвольно, то есть каждый байт в файле output.txt
должен совпадать с соответствующим байтом в answer.txt
. В таких задачах очень важно правильно отформатировать ответ, добавить все необходимые символы пробела и перехода на новую строку.
В некоторых задачах значения сравниваются в соответствии с их типом, то есть числа сравниваются как числа, а строки как строки.Это позволяет сравнивать ответы с определенной точностью (например, когда в задаче сказано выведите число с 5 знаками после запятой) илинезависимо от регистра букв в ответе (к примеру, зачисляются ответы YES
, Yes
и yes
). В таких задачах, дополнительные символы пробела и перехода на новую строку не будут влиять на результат.
В задачах в которых может быть больше одного правильного ответа используются чекер, который написан специально для данной задачи. Чекер такого типа обычно выстраивают необходимые структуры данных в памяти и проводят детальный анализ ответа. Например, в задаче поиска кратчайшего пути в графе, чекер построит граф и попытается перейти по маршруту из ответа.
В зависимости от результата сравнения, проверка может завершиться с результатом "Засчитано" или "Неверный ответ".В некоторых задачах программа проверки может засчитывать частичные баллы за результат "Неверный ответ", но на сегодняшний день таких задач на сайте не много.
На этом этапе система очищает рабочую папку (удаляет все файлы, кроме тех, которые необходимы для запуска) и начинает проверку следующего теста.
После запуска каждого теста система отправляет результаты тестирования обратно на сайт.
После последнего теста тестирующая система удаляет рабочую папку и окружение и делает запрос на получение следующего решения из очереди.
Наборы тестов
С недавнего времени на сайте появилась возможность использования наборов тестов. Возможно вы видели, что вместо простого списка, некоторые тесты теперь объединены в наборы.
Наборы тестов -- это группы тестов, объединенных вместе. Наборы задаются автором задачи для того, чтобы разделить задачу на несколько подзадач. Каждая из подзадач представляет частный случай для задачи. Например, каждая подзадача может иметь различные ограничения на значения входных данных, первая использует данные из промежутка 1 до 100, а вторая от 101 до 1000. Набор с номером 0 обычно представляет тесты из условия.
Каждый набор тестов имеет настройки оценки и отображения.
Существует два варианта оценки наборов тестов: каждый тест отдельно или набор в целом. В первом варианте вы получаете баллы за каждый тест, независимо от того удалось ли вам пройти другие тесты в наборе. Во втором варианте вам необходимо пройти все тесты набора, чтобы получить баллы. Если хотя бы один тест не пройден, весь набор не принесет вам ни одного балла.
Другая функция наборов тестов - сокрытие результатов тестирования. В зависимости от настроек задачи, тесты набора могут быть видимыми или скрытыми. Если результаты тестирования скрытые, результаты набора отражаются следующим образом:
Если все тесты набора засчитаны, отображается результат "Засчитано" и максимальные значения по использованию времени и памяти.
Если в наборе есть тесты, которые не прошли, отображается результат первого незасчитанного теста, его время выполнения и использования памяти.
Дополнительно наборы могут иметь зависимости между собой. Автор задачи может настроить наборы тестов так, что вам необходимо булет пройти все тесты одного набора, чтобы началось тестирование другого. Иначе набор будет показан со статусом "Заблокировано".
Итак, наборы могут быть оценены по-тестово или целиком, могут быть открытыми или скрытыми, а также могут иметь зависимости между собой. Все эти настройки выбирает автор задачи, чтобы получить необходимый уровень сложности и систему оценки.
Интерактивные задачи
Для проведения последнего этапа Всеукраинской олимпиады по программированию, на сайте также были реализованы так называемые интерактивные задачи.Это специальные задачи в которых вместо файлов input.txt
и output.txt
применяется специальная программа интерактор.
В целом процесс проверки соответствует тому, который описан выше, с той разницей, что во время проверки ваша программа запускается параллельно с программой интерактором, созданной автором задачи.Программы запускаются таким образом, что программа интерактор передает входные данные вашей программе, а выходные данные, которые генерирует ваша программа, передаются в программу интерактор.
Это позволяет создавать динамические тесты, в которых ваша программа может делать запросы к программе интерактору и получать динамические ответы.
Результаты тестирования зависят от результата, который возвращает программа интерактор. Если вы предоставили правильный ответ, программа интерактор передаст сигнал "Засчитано" к тестирующей системе или сигнал "Неверный ответ", если ответ не правильный.
Задачи с поиском ответа (output only)
Обычно в условии каждой задачи предоставлен один или несколько примеров для того, чтобы вам было проще увидеть формат входных данных и лучше понять задачу.А вот тесты, которые используются для оценки и проверки решения -- не доступны. То есть вам не просто нужно посчитать ответ к задаче, а создать такой алгоритм, который будет работать для любого набора входных данных.
Но на сайте существуют задачи другого типа, задачи в которых вам предоставлены все входные данные и вам просто необходимо найти ответ. В таких задачах, у вас нет ограничений на время выполнения или использования памяти. Вы можете запускать программу как угодно и сколько угодно раз. Теоретически вы даже можете подсчитать ответ вручную, без написания программы.Важен только ответ, который вы сможете получить.
Для того чтобы отправить ответ к задачам такого рода, вам необходимо отправить решение, указав язык программирования "Plain Text". В таком случае, во время проверки, система просто создаст файл с ответом output.txt
.