Тестирование софта - статьи

         

Что такое PDL


PDL (Portable Dynamic Loader) - это легкая, простая и портабельная библиотека, предназначенная для создания и использования динамически загружаемых объектов классов.



Для чего же нужна динамическая загрузка классов


Основное применение этой технологии - это разработка динамически подключаемых плагинов, расширяющих функциональность основной программы. Главная проблема состоит в том, что динамически загружаемые библиотеки на многих платформах качественно поддерживают только процедурный стиль программирования, а с загрузкой и использованием экземпляров классов возникают разнообразные проблемы. Большинство этих проблем (но, к сожалению, пока не все) и решает библиотека PDL.

На платформе Win32 PDL является сильно упрощённой альтернативой использованию технологии COM, без счётчика ссылок, без глобальной регистрации классов и множества других возможностей. Для Unix/Linux платформ существуют аналогичные библиотеки, например, С++ Dynamic Class Loader. Поддержка динамической загрузки классов присутствует и в крупной кросс-платформенной библиотеке WxWidgets.

Целью разработки PDL было создание именно кроссплатформенной библиотеки, которая позволила бы использовать один и тот же код загрузки классов для Win32 и Unix/Linux платформ (в отличие от COM и C++ Dynamic Class Loader). В то же время, библиотека должна была быть максимально независимой и легковесной (поэтому была забракована WxWidgets).

Использование динамически загружаемых классов


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

Для начала нам потребуется инстанция динамического загрузчика классов - PDL::DynamicLoader. Этот класс представляет собой синглтон, т.е. существует всегда в единственном экземпляре. Для получения ссылки на этот экземпляр используем статический метод DynamicLoader::Instance():

Код

PDL::DynamicLoader & dynamicLoader = PDL::DynamicLoader::Instance();

Далее, нам нужно загрузить инстанцию класса и получить указатель на неё:

Код

MyTestInterface * instance =
    dynamicLoader.GetClassInstance< MyTestInterface >( myLibName, "MyTestClass1" );

Здесь myLibName - это имя библиотеки-плагина, например "MyTestClass1.dll" или "MyTestClass.so". Не забываем подключить заголовочный файл с определением интерфейса класса - в нашем случае это MyTestInterface.hpp, упомянутый выше.

Наконец, вызываем метод загруженного класса:

Код

instance -> DoSomething();

Так как динамический загрузчик в случае ошибки выбрасывает исключения типа PDL::LoaderException, будет правильно обернуть его вызовы в блок try/catch. Полный код примера будет выглядеть так:

Код

#include <MyTestInterface.hpp>
#include <stdio.h>

try
{
    PDL::DynamicLoader & dynamicLoader = PDL::DynamicLoader::Instance();
    MyTestInterface * instance =
        dynamicLoader.GetClassInstance< MyTestInterface >( myLibName, "MyTestClass1" );
    instance -> DoSomething();
}
catch( PDL::LoaderException & ex )
{
    fprintf( stderr, "Loader exception: %s\n", ex.what() );
}

Следует отметить ещё один интересный момент: все динамически загруженные классы ведут себя как синглтоны. Иными словами, при повторном вызове DynamicLoader::GetInstance() с тем же именем библиотеки и с тем же именем класса будет возвращён указатель на уже загруженный экземпляр.
Это сделано для облегчения контроля удалением инстанций динамически загружаемых классов. Если потребуется создавать множество инстанций классов, рекомендуется реализовать фабрику классов и сделать её динамически загружаемой.А как же удаляются инстанции загруженных классов? Для этого и существует метод DynamicClass::Destroy(). Вызывать напрямую его не нужно - это делает сам загрузчик в своём деструкторе, либо при вызове метода DynamicLoader::Reset(). Почему же не вызывается обычный деструктор? Дело в том, что некоторые тонкости механизма выделения динамической памяти меняются от компилятора к компилятору. Представим себе, что плагин собран компилятором A, а основная программа, использующая его - компилятором B. Если мы загружаем класс из плагина, его инстанция создаётся кодом, сгенерированным компилятором A. И если мы попытаемся удалить эту инстанцию из кода основной программы просто вызвав деструктор, то удалить её попытается код, сгенерированный компиляторов B. И тут возможны казусы.Для того, чтобы избежать подобных проблем, деструктор ~DynamicClass() сделан защищённым, а вместо него следует вызывать метод DynamicClass::Destroy(). Это метод будет гарантирует, что код деструктора класса скомпилирован тем же компилятором, что и код его конструктора.

Ложка дёгтя


Есть один тонкий момент, связанный с именами библиотек. Если имя библиотеки меняется, то считается, что это уже совершенно другая библиотека, хотя по-разному записанные имена могут указывать на одну и ту же библиотеку. Например: C:\MyProg\libs\mylib.dll и MyLIB.DLL.

Следует отметить также, что библиотека PDL не решает проблемы с различным декорированием имён методов различными компиляторами - такая задача в настоящий момент не ставится.

В настоящий момент библиотека оттестирована на платформах:
FreeBSD 6.2
Debian 4.0 Linux 2.6.18-4
openSUSE 10.2
Windows XP
Я буду благодарен за любую информацию относительно работы PDL на других платформах.

Создание динамически загружаемого класса


Итак, рассмотрим подробно процесс создания динамически загружаемого класса с использованием библиотеки PDL. Прежде всего, следует определить интерфейс класса, через который мы будем работать с экземпляром загруженного класса. Обязательное условие: этот интерфейс должен наследоваться от класса PDL::DynamicClass. Давайте повнимательнее присмотримся к определению DynamicClass:

Код

сlass DynamicClass
{


public:
/**
     * @brief Get class name
     * return class name
     */
    virtual const char * GetClassName() const throw() = 0;
    
    /**
     * @brief Destroy class instance
     */
    void Destroy() throw() { delete this; }

protected:
    /**
     * @brief Destructor
     */
    virtual ~DynamicClass() throw() {;; }
};

Чисто виртуальная функция GetClassName() возвращает имя класса. Вам не нужно беспокоиться о её определении, чуть ниже я объясню почему.

Невиртуальная функция Destroy() служит для уничтожения экземпляра класса. При этом сам деструктор сделан защищённым, чтобы предотвратить его прямой вызов. Зачем именно это сделано, будет также объяснено ниже.

Итак, наш интерфейс мы должны унаследовать от PDL::DynamicClass и определить в нём виртуальный деструктор, желательно в секции protected (чтобы не нарушать идеологию PDL).

Кроме того, в объявлении интерфейса обязательно нужно написать макрос DECLARE_DYNAMIC_CLASS, передав ему в качестве параметра имя класса. Если посмотреть на описание этого макроса, становится очевидно его предназначение: он просто определяет виртуальную функцию GetClassName():

Код

#define DECLARE_DYNAMIC_CLASS( className ) \
public: \
    virtual const char * GetClassName() const throw() { return #className; }

Ну и напоследок, добавим в описание интерфейса объявления чисто виртуальных методов, реализующих полезную функциональность будущих динамически загружаемых классов.
Пусть в нашем случае это будет метод void DoSomething(). В итоге мы имеем следующее объявление интерфейса: Код#include <DynamicClass.hpp> сlass MyTestInterface : public PDL::DynamicClass
{
public:
    /**
     * @brief Test method
     */
    virtual void DoSomething() throw() = 0;     /**
     * @brief Declare this class dynamically loadable
     */
    DECLARE_DYNAMIC_CLASS( MyTestInterface )
}; Это объявление следует поместить в отдельный заголовочный файл, в нашем случае - MyTestInterface.hpp, потому как для обеспечения совместимости включаться он будет и при сборке динамически загружаемого класса, и при его непосредственной загрузке и использовании. Далее следует определить сам класс, унаследовав его от абстрактного интерфейса MyTestInterface и определив методы, реализующие полезную функциональность. Кроме того, класс нужно экспортировать с помощью макроса EXPORT_DYNAMIC_CLASS. Обратите внимание, что этот макрос должен находиться вне определения класса: Код#include <MyTestInterface.hpp>
#include <stdio.h>class MyTestClass1 : public MyTestInterface
{
public:
    /**
     * @brief Test method
     */
    void DoSomething() throw()
    {
        fprintf( stderr, "MyTestClass1::DoSomething()\n" );
    }
};EXPORT_DYNAMIC_CLASS( MyTestClass1 ) Взглянем на определение макроса EXPORT_DYNAMIC_CLASS (файл DynamicClass.hpp): Код#define EXPORT_DYNAMIC_CLASS( className ) \
extern "C" PDL_DECL_EXPORT PDL::DynamicClass * Create##className() \
{ \
    try { return new className(); } \
    catch( ... ) {;; } \
    return NULL; \
}Этот макрос объявляет и определяет экспортируемую функцию Create<имя_класса>, которая создаёт и возвращает экземпляр указанного в параметре класса.


Модификатор extern "C" нужен для того, чтобы компилятор не декорировал имя функции в библиотеке. Макрос PDL_DECL_EXPORT объявляет функцию экспортируемой. Он определён в файле platform.h и его реализация зависит от конкретной платформы.Следует обратить внимание на две вещи. Во-первых, в экспортируемой функции ловятся все исключения конструктора. В случае, если вызов конструктора аварийно завершился выбросом исключения, функция просто вернёт NULL. Это связано со сложностями, возникающими при попытке обработать в основном коде исключение, выбрасываемое кодом плагина. Во-вторых, экспортируемая функция возвращает указатель на PDL::DynamicClass, к которому неявно преобразовывается созданный объект класса. Таким образом, если мы забудем унаследовать интерфейс создаваемого класса от PDL::DynamicClass, компилятор напомнит нам об этом.После того, как класс создан, мы можем скомпилировать плагин. Следует отметить, что один плагин может содержать несколько различных динамически загружаемых классов, главное условие: они должны иметь уникальные в рамках этого плагина имена. Не следует забывать, что экспортировать при помощи макроса EXPORT_DYNAMIC_CLASS нужно каждый из классов.

Использование интерпретируемого кода


Еще одним подходом к обеспечению переносимости приложений является написание программного кода на интерпретируемых языках, использование которых не подразумевает создания исполняемых файлов в формате целевой операционной системы. Вместо этого интерпретатор последовательно считывает и выполняет инструкции непосредственно из текста программы.

Прямолинейная интерпретация достаточно неэффективна — у интерпретатора практически нет возможностей для оптимизации кода. Для повышения эффективности во многих языках (Java, Perl, Python, семейство .NET) исходный код сначала транслируется в некоторое промежуточное представление (байт-код), который уже подается на вход интерпретатору. Стадия получения байт-кода фактически является разновидностью компиляции, и при ее осуществлении могут выполняться различные оптимизирующие преобразования. Однако и в этом случае зачастую не удается достигнуть производительности, присущей «родным» для системы приложениям, поскольку определенная часть времени тратится на разбор байт-кода и транслирование его в вид, подходящий для исполнения в целевой среде.

Большей производительности удается достигнуть при использовании компиляции “на лету” (Just In Time compilation), когда байт-код транслируется в машинный код во время работы программы. Однако разработчикам JIT-компиляторов также приходится идти на компромисс между временем, уходящим на оптимизацию, и эффективностью получаемого кода, в результате чего производительность приложений может уступать коду, создаваемому “обычными” компиляторами. Кроме того, использование данной технологии увеличивает потребление памяти приложением, поскольку оттранслированный код также хранится в оперативной памяти. Также следует иметь в виду, что эффективность реализации интерпретаторов, также как и JIT-компиляторов, на различных платформах может отличаться.

Использование эмуляторов ABI


Говоря о бинарной переносимости, мы уже упомянули, что в ряде случаев операционная система может обеспечивать бинарную совместимость с другой системой за счет дополнительного слоя совместимости. При этом большинство существующих реализаций ограничивается обеспечением совместимости в рамках систем одного производителя. Из других примеров можно выделить поддержку запуска исполнимых файлов Linux в системе FreeBSD. Сам Linux также имел поддержку запуска исполнимых файлов других UNIX-систем, хотя эта функциональность не оказалась востребованной.

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

В качестве примера можно привести wine , предназначенный для запуска Windows-приложений в Linux, а также cygwin , обеспечивающий переносимость в обратную сторону. При этом, например wine достаточно легко использовать как часть приложения, не полагаясь на его доступность в целевой системе.

Недостатком использования такого рода эмуляторов является потенциальная неполнота реализации интерфейса, необходимого приложению. Так, разработчики того же wine ориентируются на публично доступную информацию об API Windows (например, стандарт ECMA-234); так что если приложение использует какие-то недокументированные возможности этой ОС, то попытка его запуска в wine может оказаться неудачной.

Отметим, что для достижения высокой производительности программы-эмуляторы зачастую используют достаточно низкоуровневые способы взаимодействия с системой, что, в свою очередь, ограничивает их собственную переносимость. Так, тот же wine содержит достаточно много кода на языке ассемблера архитектуры x86. Соответственно, использование этого эмулятора возможно либо в непосредственно x86 системах, либо в системах, предоставляющих возможность запуска x86 приложений. Поэтому при стремлении охватить большое число различных программно-аппаратных платформ, может возникнуть необходимость разных эмуляторов на различных системах.

Кроме того, в определенных ситуациях прямолинейное использование эмуляторов по определению дает менее эффективные продукты, чем те, что используют «родные» средства целевой системы. В качестве примера можно привести уже упоминавшуюся ранее среду разработки Borland Kylix для Linux, основанную на использовании эмулятора wine. Косвенно использование эмулятора в этом случае означает использование тех же методик создания программ, которые применяются в исходной системе — ОС Windows. Однако, как показала практика, эмуляция этих методик не выдерживает конкуренции с аналогичными средствами ОС Linux — в частности, с компилятором GCC (прежде всего, в плане производительности программ, получаемых с помощью среды Kylix).

Использование Web-технологий


Становящиеся с каждым годом все популярнее web-технологии также могут быть использованы для повышения переносимости программных продуктов. Можно выделить два основных способа построения приложений, использующих эти технологии: создание полностью локального приложения, располагающегося на машине пользователя, и использующего web-браузер для взаимодействия с ним; реализация приложения в виде сервиса; при этом серверная и клиентская части приложения могут быть разнесены на разные машины.

Такое разделение довольно условно, поскольку в первом случае приложение также, как правило, имеет серверную и клиентскую части, и может допускать подключение клиентов с других машин. Например, подобным образом устроен Web-интерфейс сервера печати CUPS (Common Unix Printing System), который может быть использован для настройки принтеров как на локальной, так и удаленных машинах.

В любом случае, использование web-браузера и сопутствующих инструментов облегчает задачу разработки графического интерфейса пользователя. Программа может либо создавать HTML-представление интерфейса, непосредственно интерпретируемое браузером, либо использовать технологии типа Flash, Silverlight и JavaFX, позволяющие создавать интерактивные файлы, для воспроизведения которых достаточно наличия соответствующего проигрывателя на целевой платформе. Зачастую такой проигрыватель встраивается в браузер как расширение.

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

Использование web-браузера для отрисовки графического интерфейса имеет как преимущества, так и недостатки. К преимуществам, помимо упомянутого выше снижения затрат на разработку, стоит отнести возможность настройки интерфейса пользователем по своему вкусу — изменением шрифтов, масштаба страницы и т.п.
Основной недостаток подхода является следствием его достоинств — в разных браузерах одна и та же страница может отображаться по-разному — как вследствие пользовательских настроек, так и из-за особенностей конкретного браузера. Безусловно, существуют различные стандарты на HTML, CSS, JavaScript и прочие элементы, используемые при отображении web-документов, однако разные браузеры соответствуют этим стандартам в разной степени . Поэтому разработчикам приходится либо проводить тестирование на различных браузерах , либо ограничиваться поддержкой только некоторых из них. Для автоматизации процесса тестирования существуют различные свободно доступные инструменты — например, сервис BrowserShots позволяет получить снимки экрана с видом заданной страницы в различных браузерах (на данный момент доступно более 80) в Linux, Mac OS и Windows. Также отметим, необходимость создания больших распределенных систем привела к созданию архитектур, более сложных, чем клиент-серверная, и подразумевающих взаимодействие множества компонентов различной структуры. Исследования проблем разработки сложных программных комплексов привели к разработке парадигм, подразумевающих разбиение системы на отдельные компоненты, которые взаимодействуют друг с другом по строго определенным протоколам. При таком подходе каждый компонент не только может работать на отдельной машине, но также разрабатываться независимо от других. При этом (в идеале) процесс переноса компонента на другую платформу либо замена его на альтернативную реализацию никак не затрагивает других частей системы. К одной из первых попыток описания механизма взаимодействия компонентов распределенной системы можно отнести спецификацию CORBA (Common Object Request Broker Architecture), разработанную консорциумом OMG . Однако CORBA в силу ряда причин не снискала большой популярности, и в настоящее время гораздо больший интерес проявляется к web-сервисам, использующим протоколы обмена сообщениями на базе XML. При проектировании сложных распределенных программных комплексов используется парадигма сервисно-ориентированной архитектуры (Service-oriented architecture, SOA ); при этом программные комплексы часто реализуются как набор web-сервисов.

Литература


James D. Mooney. "Bringing Portability to the Software Process". // Technical Report TR 97-1, Dept. of Statistics and Computer Science, West Virginia University, Morgantown WV, 1997. Ian Sommerville. Software Engineering, 8th Edition, Addison Wesley, 2006. Wikipedia, the free encyclopedia. IBM System/370. http://en.wikipedia.org/wiki/System/370 Wine - Open Source implementation of the Windows API. http://www.winehq.org/ Borland's Net Loss Desaster. // Архив дискуссионного листа «borland.public.delphi.non-technical». Август 2005. http://coding.derkeiler.com/pdf/Archive/Delphi/borland.public.delphi.non-technical/2005-08/msg01903.pdf Ryan Slobojan. Tasktop 1.3: Support Added for Firefox and Linux. // InfoQueue News. Nov 12, 2008. http://www.infoq.com/news/2008/11/tasktop-13 Apple Rosetta. http://www.apple.com/rosetta/ Андрей Ященко. 64-x битные процессоры. // 3DNews, 7 августа 2003. http://www.3dnews.ru/cpu/cpu-64/index2.htm Cygwin - Linux-like environment for Windows. http://www.cygwin.com/ Gerald J. Popek, Robert P. Goldberg. Formal Requirements for Virtualizable Third Generation Architectures. // Communications of the ACM, Volume 17, Issue 7, July 1974, pp. 412-421. Крис Касперски. Аппаратная виртуализация или эмуляция "без тормозов". http://www.insidepro.com/kk/159/159r.shtml Virtual Box. http://www.virtualbox.org VMware. http://www.vmware.com Matias Zabaljauregui. Hardware Assisted Virtualization. Intel Virtualization Technology. Buenos Aires, June 2008.http://linux.linti.unlp.edu.ar/kernel/wiki/images/f/f1/Vtx.pdf AMD Virtualization. http://www.amd.com/us-en/0,,3715_15781,00.html Paul Barham, Boris Dragovic, Keir Fraser, Steven Hand, Tim Harris, Alex Ho, Rolf Neugebarger, Ian Pratt and Andrew Warfield. Xen and the Art of Virtualization. // Proceedings of the 19th Symposium on Operating Systems Principles, October 2003. Daniel J. Magenheimer, Thomas W. Christian. vBlades: Optimized Paravirtualization for the Itanium Processor Family. // Proceedings of the 3rd Virtual Machine Research & Technology Symposium. May, 2004. pp 73–82, USENIX. Linuxgym Teaching System. http://www.linuxgym.com/ Tom Dahm. Browser Compatibility Tutorial. http://www.netmechanic.com/products/Browser-Tutorial.shtml Browser Tests, Services and Compatibility Test Suites. // Smashing Magazine, October 2007. http://www.smashingmagazine.com/2007/10/02/browser-tests-services-and-compatibility-test-suites/ http://browsershots.org/ OMG CORBA 3.0. http://www.omg.org/ technology/documents/formal/corba_2.htm Ben Margolis, Joseph Sharpe. SOA for the Business Developer: Concepts, BPEL, and SCA. MC Press, 2007.


Методы обеспечения переносимости ПО


,
Труды Института системного программирования РАН

Переиспользование бинарных файлов


Перенос приложения на новую программно-аппаратную платформу может пройти безболезненно для разработчиков, если старая и новая системы совместимы на бинарном уровне, то есть новая система поддерживает двоичный интерфейс приложений (Application Binary Interface, ABI), что позволяет использовать старые двоичные файлы приложения без каких-либо изменений. Можно выделить две основные составляющие ABI: форматы исполняемых файлов и библиотек; набор библиотек и их функций, предоставляемых системой.

Совместимость форматов является критичной для возможности использовать двоичные файлы без изменений. При этом формат файлов достаточно сильно связан с аппаратной частью платформы, на которой функционирует система - в силу технических причин (разный размер указателей, различный порядок нумерации разрядов и т.п.) в общем случае сложно достичь совместимости систем, работающих на различных архитектурах.

Что касается наборов библиотек и их функций, то их полной идентичности в различных системах ожидать трудно, однако во многих случаях пересечение множеств предоставляемых функций является достаточно большим.

Многие производители операционных систем в настоящее время заботятся об обратной совместимости своих продуктов на бинарном уровне — гарантируется, что приложение, работающее в некоторой версии ОС, будет работать без перекомпиляции в более новых версиях системы на той же аппаратной архитектуре.

В ряде случаев поддерживается возможность запуска приложений, написанных для той же системы, но на другой платформе — так, операционная система MacOS X, работающая на компьютерах Apple с процессорами Intel, использует динамический транслятор Rosetta для выполнения программ, предназначенных для машин с процессорами PowerPC . Однако пользоваться такой возможностью следует с осторожностью. Во многих случаях совместимость обеспечивается за счет некоторого дополнительного слоя совместимости между системой и приложением, который может и не гарантировать полной совместимости — так, уже упомянутая Rosetta позволяет исполнять код для процессоров G3, G4 и AltiVec, но не для G5. Кроме того, дополнительный компонент системы является дополнительным потенциальным источником ошибок, а использование посредника в общем случае снижает производительность. Например, процессор Itanium способен выполнять код, созданный для платформы x86, однако производительность его в этом случае может уступать оригинальному x86 процессору с такой же тактовой частотой .

Переиспользование исходного кода


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

Исторически, возможность переноса исходного кода между различными платформами появилась не сразу. В те времена, когда программы писались на ассемблере конкретной аппаратной платформы, добиться компиляции приложения на системе с другой архитектурой было практически нереально. Существенной подвижкой в этом направлении стало создание высокоуровневых языков программирования, не привязанных к конкретной архитектуре и позволяющих использовать одни и те же конструкции на различных системах. Например, именно озабоченность некоторых сотрудников AT&T Labs проблемой переносимости ОС UNIX на новые аппаратные платформы привела к созданию языка Си.

Для обеспечения возможности использования одного и того же кода целевые системы должны предоставлять компиляторы для соответствующего языка программирования, вместе с необходимыми библиотеками. Естественно, что компиляторы для различных систем создаются различными производителями и могут достаточно сильно отличаться друг от друга. Такие отличия следует учитывать при написании кода.

Частично эта задача облегчается следованием международных стандартов, разработанных для многих языков программирования. Однако далеко не все компиляторы поддерживают стандарты в полном объеме (хотя, как правило, не поддерживаются некоторые специфические конструкции языка, в плане же предоставления библиотечных функций ситуация гораздо лучше). Другой проблемой является относительная узость стандартов — несмотря на наличие во многих из них перечня функций, которые должны предоставляться любой удовлетворяющей стандарту средой разработки, эти перечни не описывают существенную часть функциональности, которая могла бы быть полезна при создании приложений — например, функции графического интерфейса, либо функции работы с мультимедиа.

Помимо стандартов языков программирования, существуют стандарты, описывающие интерфейс прикладных программ (API, Application Programming Interface) — например, POSIX.
Однако такие стандарты также, достаточно узки, и являются недостаточными для написания большинства приложений. В случае, если необходимая приложению функциональность не охватывается ни одним из стандартов, могут быть использованы продукты сторонних разработчиков, существующие на всех целевых системах и предоставляющие необходимые возможности. Такой продукт выступает в роли медиатора между приложением и операционной системой, скрывая от приложения процесс взаимодействия с последней. Характерным примером подобных продуктов являются кросс-платформенные библиотеки графического интерфейса пользователя — такие, как Qt, Gtk или wxWidgets. Реализация этих библиотек присутствует во всех основных операционных системах (FreeBSD, Linux, Windows, MacOS), а функции API, доступные программистам, практически идентичны для всех платформ. Кроме того, либеральность лицензий позволяет использовать эти библиотеки при создании достаточно большого спектра приложений. Если же медиатора, способного удовлетворить нужды разработчиков, не нашлось, то может быть целесообразно создать свой собственный, который можно будет использовать во многих продуктах компании. Такой подход оправдан, если можно четко выделить функциональность, которую должен предоставлять медиатор, и отделить реализацию этой функциональности от остальных частей продукта. Так, разработчики Mozilla в свое время решили создать собственный набор библиотек поддержки различных стандартов безопасности (в результате появился набор Network Security Services, NSS), а также собственную кросс-платформенную библиотеку, реализующую достаточно низкоуровневые функции (работы с потоками, памятью, вводом-выводом и т.п.). Результатом второй инициативы стало создание библиотеки NSPR (NetScape Portable Runtime). Отметим, что поскольку и NSS, и NSPR, являются продуктами с открытым исходным кодом, их использование в настоящее время не ограничивается проектами, разрабатываемыми Mozilla Foundation.

Примеры из современности


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

В начале 2000-х годов компания Borland решила обратить свой взор на ОС Linux и выпустила среду разработки Kylix — аналог Delphi и C++ Builder. Такой шаг был изначально положительно оценен Linux-сообществом (даже несмотря на то, что Kylix не являлся продуктом с открытым исходным кодом, а бесплатной была только базовая версия системы) — в то время в этой ОС не было сравнимых по функциональности аналогов упомянутых программ.. Однако в основе Kylix лежал исходный код соответствующих сред разработки для ОС Windows, а для запуска на Linux использовался эмулятор wine. Как показала практика, такой прямолинейный перенос, как использование эмулятора, не привел к созданию конкурентноспособного продукта — довольно быстро выяснилось, что wine не является достаточно надежным, чтобы гарантировать его стабильность . Разработчикам приходилось иметь дело как с ошибками в своих программах, так и с некорректным поведением эмулятора. Ввиду закрытости проекта сложно оценить, насколько затратен был бы перенос программ на использование «родных» библиотек Linux; но основываясь на том факте, что работа над Kylix была заморожена, можно предположить, что задача оказалась слишком ресурсоемка.

Другой пример недальновидного подхода к этому вопросу проявился в ходе организации проекта по разработке пакета свободного программного обеспечения (СПО) для образовательных учреждений России. Практически все программное обеспечение, которое разрабатывалось по заказу Министерства образования РФ в последние годы было предназначено для работы исключительно на платформе Microsoft Windows. Поэтому при внедрении пакета СПО на основе операционной системы Linux большая часть разработанных ранее образовательных программ оказалась недоступна, и только часть из них удавалось запустить с помощью эмулятора wine .

Схожие проблемы возникали и в стане разработчиков web-приложений.
Известно несколько случаев, когда при разработке интернет-сервисов заказчик ограничивался требованием совместимости с браузером Internet Explorer, а через некоторое время под давлением клиентов был вынужден дорабатывать ПО для поддержки набирающего популярность Mozilla Firefox. Например, на основе опроса пользователей приложения Tasktop о желаемых нововведениях, проведенного в 2008 году, выяснилось, что наиболее востребованными являются поддержка ОС Linux и браузера Firefox. Реализация этих свойств стала приоритетным направлением разработки, и была представлена пользователям уже в ноябре 2008 года, в Tasktop 1.3 . Отметим, что добавление такого нетривиального свойства, как поддержка новой операционной системы, не заняло много времени, поскольку основная часть приложения написана на интерпретируемом языке Java, а виртуальные машины для исполнения этого кода существуют как в Windows, так и в Linux. Более того, разработчики Tasktop планируют портировать свой продукт и на MacOS — ввиду наличия в этой ОС виртуальной машины Java, такая задача также не представляется слишком сложной. Приведенные примеры демонстрируют, что изначальная нацеленность на создание переносимого продукта позволяет достаточно безболезненно портировать его на платформы, поддержка которых изначально не планировалась (либо которых просто не существовало в момент начала разработки). Это позволяет производителям не оставаться в стороне от стремительного развития рынка и своевременно реагировать на запросы пользователей. В то же время невнимание к проблеме переносимости может привести к различным негативным техническим, экономическим и политическим последствиям: проблемам с поддержкой ПО в долгосрочной перспективе; сокращению доступных рынков и недополучению прибыли; попаданию в зависимость от одного поставщика. Как мы уже отметили, проблема известна давно, и за время эволюции программного обеспечения появилось достаточно много подходов к созданию приложений, переносимых между различными системами. Рассмотрим те из них, что представляются наиболее популярными.

Тестирование софта - статьи


Аннотация. Статья посвящена проблеме переносимости приложений между программно-аппаратными платформами. Предлагается обзор подходов к решению этой проблеме, появившихся за время развития ИТ, а также анализ преимуществ и недостатков каждого из них. Рассматриваются области применения существующих решений.

Виртуализация


Альтернативой эмуляции ABI некоторой системы является запуск копии такой системы внутри основной ОС, с использованием программ, эмулирующих аппаратное обеспечение — виртуальных машин. На такой машине устанавливается операционная система и другое окружение, необходимое приложению, а само приложение запускается уже в родной для него среде.

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

В общем случае использование виртуальной машины достаточно ресурсоемко — ведь помимо собственно приложения, ресурсы компьютера потребляются самой машиной, а также работающими внутри нее программами, необходимыми для функционирования приложения (например, операционной системой). Поэтому выигрыш в производительности достигается, как правило, только в случае запуска машин, эмулирующих достаточно маломощные платформы на более производительных системах.

Проблеме производительности виртуальных машин уделялось много внимания еще в 70е годы. Впервые требования, которым должна удовлетворять аппаратная архитектура машины, чтобы на ней можно было эффективно реализовать виртуализацию, были сформулированы Попеком и Голдбергом в 1974 году . Основное требование сводится к разделению всех инструкций по разным уровням привилегий; при этом все инструкции, способные изменить состояние ресурсов виртуальной машины, а также инструкции, поведение которых зависит от конфигурации этих ресурсов, должны быть привилегированными. Монитор виртуальных машин (Virtual Machine Monitor, VMM — программная прослойка, занимающаяся распределением физических ресурсов между работающими виртуальными машинами), сам работая с наивысшими привилегиями, может перехватывать эти инструкции и эмулировать их поведение в соответствии со своими потребностями.
Все непривилегированные инструкции должны выполняться непосредственно на аппаратуре. Поскольку доля привилегированных инструкций, как правило, невелика, то и затраты на их эмуляцию будут малы. Несмотря на то, что работа Голдберга и Попека посвящена машинам третьего поколения (IBM 360, Honeywell 6000, DEC PDP-10), сформулированные в ней требования справедливы и сегодня. Однако, для большинства современных архитектур приведенное выше требование не выполняется — существуют непривилегированные инструкции, влияющие на конфигурацию ресурсов либо зависящие от нее. В частности, для «классической» архитектуры x86 к числу таких инструкций относятся такие популярные инструкции, как push/pop, call, jmp и другие (более подробно данная проблема рассмотрена в ). Безусловно, построение виртуальной машины возможно и при наличии таких инструкций. Существуют подходы по определению и перехвату необходимых инструкций в процессе работы программы; по такому принципу работают популярные продукты типа VirtualBox и VMWare , старающиеся напрямую выполнять все инструкции, для которых это возможно. Тем не менее, необходимость дополнительного отслеживания выполняемых инструкций может замедлить производительность программ внутри виртуальной машины по сравнению с «живой» системой. Отметим, что осознание разработчиками важности виртуализации привело к появлению расширений от Intel (Intel Virtualization Technology ) и AMD (AMD Virtualization ) для ее поддержки на платформах x86 и x86-64, которые позволяют либо вовсе избавится, либо существенно снизить число перехватываемых и эмулируемых инструкций. Альтернативным методом борьбы с «вредоносными» инструкциями является паравиртуализация, основанная на внесении изменений в гостевую операционную систему перед ее запуском в виртуальной среде; известным примером машин, работающих по принципу паравиртуализации, является Xen . Однако в реальной жизни такая модификация не всегда доступна конечным пользователям. Существуют и гибридные подходы — например, проект vBlades для Itanium . Стоит обратить внимание и на экономическую составляющую использования виртуальной машины конечным пользователям — в ряде случаев стоимость операционной системы и компонентов окружения, которые необходимо установить, может быть довольна значительна.Поэтому достаточно редки ситуации, когда производители сами советуют использовать виртуальные машины для запуска своих программ в системах, не поддерживаемых напрямую. Примерами исключений являются различные специфические системы, безопасное функционирование которых требует запуска в изолированной среде. Например, обучающая система Linuxgym распространяет клиентскую часть в виде образа VMware, содержащего Ubuntu Linux с предустановленными необходимыми компонентами.

Проблема переносимости приложений между различными


Проблема переносимости приложений между различными программно-аппаратными платформами ненамного моложе собственно компьютерных программ. Еще в конце шестидесятых годов озабоченность некоторых сотрудников AT&T Labs проблемой переносимости ОС UNIX на новые аппаратные платформы привела к созданию языка Си. Темпы развития компьютерной индустрии таковы, что проблемы сорокалетней давности кажутся достаточно простыми и решаемыми, по сравнению с тем, что мы имеем сегодня. Стремительное развитие связанных с компьютерами отраслей приводит к постоянному появлению новых программно-аппаратных платформ, информационных систем, и т.п., в то время как устаревшие комплексы уходят в небытие. Производители ПО, как правило, заинтересованы в быстром переносе своих продуктов на новые системы, чтобы захватить соответствующую долю рынка. Если приложение изначально проектировалось с оглядкой на возможность портирования, то этот процесс может оказаться существенно дешевле создания нового продукта. Будет проще и конечным пользователям, которые в новой системе увидят то же самое приложение, с которым работали раньше, что также способствует популярности продукта. В некоторых случаях большое внимание переносимости приложений уделяется и производителями платформ, на которых эти приложения выполняются — например, одним из принципиальных аспектов при разработке IBM мэйнфрейма System/S370 в конце 60х-начале 70х годов было сохранение обратной совместимости с System/S360, с целью упростить миграцию приложений своих клиентов . Обратная совместимость с System/S360 сохранялась на протяжении всего жизненного цикла System/S370; более того, сохраняется она и в ее последователях — System/S390 и zSeries. Однако далеко не все производители столь щепетильны, и далеко не все платформы могут похвастаться столь длительным сроком жизни. Нередко с рынка уходят не только сами системы, но и их создатели, так что труднодоступными становятся не только сами системы, но и все сведения об их архитектуре. Исчезновение тех или иных платформ приводит к появлению унаследованного ПО — программных продуктов, необходимых для функционирования той или иной организации, но требующих для работы устаревшей программно-аппаратной платформы. В случае выхода из строя аппаратного обеспечения может оказаться, что найти ему замену очень сложно, дорого, а иногда и попросту невозможно, так как устаревшая ОС не работает на современном оборудовании (либо по причине принципиальных отличий архитектуры, либо по более прозаическим причинам — например, ввиду отсутствия необходимых драйверов). Для многих предприятий задача переноса таких приложений в более современное окружение является крайне актуальной .

и существует множество путей по


Если невнимание к проблеме переносимости приводит к негативным последствиям и существует множество путей по ее решению, то возникает вопрос: так почему же ИТ индустрия не переориентируется на разработку переносимого ПО? Несложно догадаться, что разработка переносимого ПО имеет свои недостатки. Среди рассмотренных видов переносимости приложений очень привлекательным с точки зрения разработчиков является перенос непосредственно бинарных файлов на новую систему, позволяющий при относительно небольших затратах (в основном уходящих на тестирование) получить на новой системе приложение, имеющее всю необходимую функциональность. При этом потери в производительности если и возникают, то совсем небольшие. Однако для любой ОС число платформ, совместимых с ней на бинарном уровне, достаточно невелико. Использование эмуляторов может расширить их круг, но эмулятор — дополнительный потенциальный источник ошибок, который при этом может и не предоставлять всех необходимых функций. Потенциально больший охват дает переносимость исходного кода. Сложность портирования в этом случае может варьироваться в зависимости от того, насколько такая возможность учитывалась при разработке приложения; полезной с этой точки зрения является ориентация на различные интерфейсные стандарты, регламентирующие взаимодействие приложения с окружающей средой. Но существующие стандарты охватывают достаточно небольшую функциональность; в ряде случаев может помочь использование кросс-платформенных библиотек, другой же альтернативой является использование интерпретируемых языков. Спецификации таких языков не привязаны к конкретной платформе и можно полагаться на то, что интерпретаторы на разных системах поддерживают один и тот же набор функций. Среди недостатков подхода можно выделить меньшую производительность по сравнению с бинарным кодом. Архитектура SOA затрагивает более сложную проблему организации сложных программных комплексов, предлагая строить их в виде набора достаточно изолированных компонентов, каждый из которых может работать на своей собственной платформе и в случае необходимости может быть перенесен на другую (либо заменен на альтернативную реализацию). Подход Примеры
Ориентация на стандарты Ряд утилит GNU (tar, wget и др.), написанные с ориентацией на POSIX
Медиаторы сторонних разработчиков Skype — использование библиотеки Qt для реализации GUI
Собственные медиаторы Mozilla Firefox — использование собственных кросс-платформенных библиотек NSS (Network Security Services) для поддержки различных стандартов безопасности
Эмуляция Google Picasa — применение wine для работы в Linux
Виртуализация Linuxgym — клиент распространяется в виде образа VMware
Таблица 1.
Примеры использования различных подходов к обеспечению функционирования приложений как в Windows, так и в Linux. Использование виртуальных машин также не требует больших усилий со стороны разработчиков ПО, хотя этот способ достаточно накладен, как в смысле производительности, так и ввиду необходимости иметь лицензии на все используемые операционные системы. Применение виртуализации оправдано в тех случаях, когда перенос приложения каким-то другим способом представляется экономически неэффективным. В частности, это относится ко многим унаследованным системам, для которых портирование на новую платформу означало бы практически полное переписывание приложения. В таблице 1 приведены примеры использования различных подходов к обеспечению переносимости ПО, которые используются разработчикам для создания программ, функционирующих как в Windows, так и в Linux. Интересно отметить подход Google, который не побоялся положиться на слой эмуляции wine для запуска Google Picasa в ОС Linux, несмотря на практически полное отсутствие успешных примеров крупных приложений, официально использующих такой метод. Подход с использованием библиотек-медиаторов более традиционен и применяется не один десяток лет. Вопрос обеспечения переносимости следует рассматривать в самом начале проекта, на стадии проектирования и выбора технологий и инструментов, которые будут использованы при его реализации. К сожалению, вряд ли можно сформулировать универсальное правило выбора средств для увеличения переносимости – такой выбор сильно зависит от конкретных требований, предъявляемых к приложению. На взгляд авторов, в настоящее время потенциально наибольший охват дает использование интерпретируемых языков – многие интерпретаторы работают на достаточно большом числе программно-аппаратных платформ. Естественно, использование таких языков имеет свои недостатки, и для ряда приложений может оказаться неприемлемым. Следующим по масштабу «охвата», на наш взгляд, идет использование кросс-платформенных библиотек и других медиаторов.


Однако медиаторов, реализующих нужную функциональность, может и не существовать, а разработка собственных – оказаться достаточно трудоемким процессом. Тем не менее, даже при отказе от поддержки нескольких систем ввиду отсутствия средств и при ориентации на одну конкретную платформу, стоит строить архитектуру приложения таким образом, чтобы по возможности отделить части, использующие специфические для данной платформы интерфейсы и сервисы. Подводя итоги, отметим, что возможны ситуации, когда отказ от обеспечения переносимости разрабатываемого ПО оправдан; например, с достаточно большой долей вероятности такой выбор будет выгоден в краткосрочной перспективе. Однако при создании продуктов, которые планируется поддерживать в течении достаточно длительного периода, обеспечение переносимости может оказаться одним из ключевых факторов успеха. Повышение мобильности приложения в общем случае всегда связано с увеличением расходов на его разработку; однако чем раньше об этой проблеме задумаются разработчики и архитекторы, тем меньше будет стоимость переноса приложения на новую платформу.

Аналогии


Есть замечательная реклама: Как делают автомобили SAAB? Берут самолёт и отсекают всё лишнее, что помогает ему взлетать.

Попробуем взять шаблон RUP-а для MTP (Master Test Plan) и отсечь всё лишнее, что не касается темы данной статьи. Самое интересное, что отсечь пришлось практически весь шаблон, оставив только одно приложение и табличку, для расчета ресурсов. Добавим перевод, вырежем лишнее.

Деятельность/Задачи тестирования (Testing Activities)


Рассмотрим более подробно существующие активности/задачи связанные с тестированием: Планирование тестов (Plan Test) Определение требований к тестам (identify requirements for test) Оценка рисков (assess risk) Разработка стратегии тестирования (develop test strategy) Определение ресурсов (identify test resources) Создание расписания/последовательностей (create schedule) Разработка Плана тестирования (generate Test Plan) Дизайн тестов (Design Test) Анализ объёма работ (prepare workload analysis) Определение и описание тестовых случаев (identify and describe test cases) Определение и структурирование тестовых процедур (identify and structure test procedures) Обзор и оценка тестового покрытия (review and assess test coverage) Разработка тестов (Implement Test) Запись или программирование тестовых скриптов (record or program test scripts) Определение тесто-критичной функциональности в Дизайне и Модели реализации (identify test-specific functionality in the Design and Implementation Model) Создание/подготовка внешних наборов данных (establish external data sets) Выполнение тестов (Execute Test) Выполнение тестовых процедур (execute Test procedures) Оценка выполнения тестов (evaluate execution of Test) Восстановление после сбойных тестов (recover from halted Test) Проверка результатов (verify the results) Исследование неожиданных результатов (investigate unexpected results) Запись ошибок (log defects) Оценка тестов (Evaluate Test) Оценка покрытия тестовыми случаями (evaluate Test-case coverage) Оценка покрытия кода (evaluate code coverage) Анализ дефектов (analyze defects) Определение критериев завершения и успешности тестирования (determine if Test Completion Criteria and Success Criteria have been achieved

Классификация задач и ролей в тестировании, основанная на методологии RUP.


Вокруг ролей и задач, связанных с тестированием и обеспечением качества, сложилось несколько противоположных идейных течений, которые усердно культивируются носителями этих идей. Точки зрения во многом противоположны, во многом противоречивы. Тестирование видится с одной стороны каким-то полумеханическим процессом, который не требует особенной квалификации: тестировщика видят эдаким «кликальщиком», который просто гоняет приложение, ждёт пока оно «упадёт», потом радостно сообщает об ошибке и продолжает в том же духе. В последнее время, надо отдать должное, появляются материалы о тестировании и качестве, выходят в свет книги, развиваются сайты посвящённые этому направлению — это направление мысли постепенно сходит на «нет». С другой точки зрения, которую, наверное, культивируют отчасти и сами тестировщики (в самом широком смысле этого слова), тестирование — это процесс, покрытый множеством неопределённостей, трудно формализируемый и поддающийся оценкам. Если же к тестированию добавить автоматизацию, которая по оценкам тех, кто внедрял инструменты и решения для тестирования, требует больших (по сравнению с ручным тестированием) трудозатрат и говорить об оценке качества продукта, направление тестирования получается совсем непрозрачным для стороннего наблюдателя, а порой и для самих тестировщиков и QA.

Как мне кажется, связана такая ситуация с тем, что существует определённое непонимание процессов связанных с тестированием и обеспечением качества. Между тем, направление тестирования чётко определено ролями и задачами, которое оно решает. Определившись с ролями и задачами, можно не только представить себе более-менее стандартный процесс тестирования, но также понять, что к нему не относится. Заметим, я не отождествляю процессы тестирования и обеспечения качества. К задачам обеспечения качества я планирую вернуться в последующих публикациях. Сейчас я предлагаю рассматривать тестирование, как часть процесса обеспечения качества.

Попробуем определиться и понять, какие же роли и задачи решаются направлением тестирования. Чтобы не изобретать велосипед, я предлагаю взять за основу существующую методологию RUP (Rational Unified Process), как наиболее общий и полный вариант.

Роли в тестировании (roles)


Роль Описание
Тест-менеджер, менеджер проекта по тестированию

(Test Manager, Test Project Manager)

Производит управленческий контроль (management oversight)

Ответственность: Обеспечивает техническое направление Получает необходимые ресурсы Обеспечивает управленческую отчётность

Тест дизайнер

(Test Designer)

Определяет, приоритизирует и обеспечивает разработку тестовых случаев

Ответственность: Разрабатывает план тестирования Разрабатывает модель тестирования Оценивает эффективность тестирования

Тестировщик, Инженер по тестированию

(Tester)

Выполняет тесты

Ответственность: Выполняет тесты Фиксирует результаты Восстанавливает тесты и систему после сбоев Документирует запросы на изменение

Администратор тестовой системы, приложений поддерживающих жизненный цикл тестирования

(Test System Administrator)

Обеспечивает управление и поддержку тестовых окружений и данных

Ответственность: Администрирует систему управления тестированием Инсталлирует и управляет доступом к тестовым системам

Администратор баз данных, менеджер баз данных

(Database Administrator, Database Manager)

Обеспечивает управление и поддержку тестовых данных (баз данных)

Ответственность: Администрирует тестовые данные (базы данных)

Тест-дизайнер

(Designer)

Устанавливает и определяет операции, атрибуты и связи тестовых классов

Ответственность: Устанавливает и определяет тестовые классы Устанавливает и определяет тестовые наборы (пакеты)

Разработчик тестов

(Implementer)

Разрабатывает юнит тесты (unit tests), тестовые классы и тестовые наборы (пакеты)

Ответственность: Создаёт тестовые классы, собирает тестовые пакеты и интегрирует их с тестовую модел

Как видите, при ближайшем рассмотрении, оказывается, что тестирование — вполне определённый процесс с выделенными ролями и зоной ответственности для различных игроков проекта. Порядок перечисления задачи определяет обычный (полный) цикл проведения тестирования. Такой цикл может применятся, как для проектов ориентированных на длительные итерации, так и для «быстрых» проектов ведущихся по эволюционным методикам (evolutionary) или согласно набирающему обороты XP.

Надеюсь, после небольшого экскурса во внутренний мир задач и ролей в тестировании, неразберихи станет меньше.

Аллилуя, то есть Славься!


Я не преследовал цели посвятить вас в самые сложные вещи Qt — точнее, таких вещей я там и не заметил. Всё ровно, логично, слаженно, сбито и задокументированно. Конечно, были и будут баги, возникают новые возможности — но для этого есть огромное сообщество разработчиков, да и конфы в Сети просто ужасно большое количество. В общем, с проблемами не "подвиснете". Кстати, и исходный код можно посмотреть, если уж что-то совсем непонятно, а при желании можно даже частично перекомпилировать. Этого я, правда, делать не советую — расстанетесь с совместимостью. Лучше станьте контрибьютором — а там, чего доброго, дорастете до должности "платного друга Trolltech", я бы гордился.

В заключение хочу сказать, что в процессе "кьютизаци" вы можете круто сэкономить на интернете — на КП-диске лежат отличные фрагменты видео, поясняющие концепции Qt, что называется, устами создателей. Там же — whitepapers. Там же — триальные инсталляшки Qt и QSA для Windows и X11. Для регистрации триала зайдите на сайт и зарегистрируйтесь без закачки, ключи придут по почте. Бесплатные версии для Линукс лучше всего закачать с сайта дистрибутива в виде пакета, чтобы не морочиться с компиляций — в последние дистро все и так наверняка включено, просмотрите список доступных пакетов, если что.

Короче: надумаете начинать новый портабельный "высокооктановый" проект… ну вы уже поняли, что делать. После "пингвинизации" Китая компанией Sun (контракт на поставку 200 миллионов пингвинов…) вам будет просто скучно писать для MS Windows. Хотя, с другой стороны, Билла Гейтса тоже еще никто не отменял, так что не без этого — лучше сохранять совместимость.

Кстати, кто первый создаст аутсорсинг "QTWorks.ua" — тот может реально подрубить не только у нас на районе, но и в окружающих поселениях, типа России, Германии и Кореи, поскольку в ближайшее время значение Linux-приложений во "взрослых" странах будет только расти.

В статье использованы материалы и примеры с сайта trolltech.com.

Библиотека, learning curve


Как я уже говорил, Qt — это библиотека классов. Классов там более четырехсот, так что, если начальник требует, чтобы вы начали кодить на Qt с завтрашнего дня, то лучше послать его к ежам. Придется, как минимум, пару недель изучать доки, а лучше прочитать книжку. Я за целую ночь не смог воткнуть даже простецкие вещи. Вам тоже торопиться не советую, лучше делать все правильно — от простого к сложному.

Может быть, не первая по важности, но несомненно нужная после инсталляции вещь — просмотр, распечатка, (а возможно, и татуировка на груди — вверх ногами, чтобы читать было удобно) иерархии классов Qt.

Это, в общем-то, относится к любой библиотеке. Но в некоторых "системах ценностей" вы можете прожить три жизни, и проходить при этом "в лаптях", то есть использовать 3% от всех возможностей, обходя стороной то, что, собственно, и составляет ценность продукта. Пример: множество малопонятных функций в MS Exсel, масса никому не нужных ActiveX-компонент (помните, как они продавались почти по одной штучке — во цирк!) и т.д. В Qt все несколько иначе — вы в конце концов будете использовать 50-80% всех классов, так что "отбыть номер" не удастся.

На приведен сильно уменьшенный вариант этой самой схемы — но вы можете распечатать и большой вариант. Он расположен по адресу и, кроме того, лежит прямо здесь.

Непременно прочитайте whitepapers — в отличие от других "белок", это не просто набор рекламных лозунгов. После чтения приведенных там примеров вы даже сможете построить несколько приложений.

Как маршрут для вечерних прогулок вы должны избрать посещение сайта — вас там многое заинтересует, начиная, конечно, с How To Learn Qt. Собственно, всегда лучше начинать с голого кодирования, не пользуясь автогенераторами — или пользуясь, но при этом тщательно разбирая код. В противном случае вы напишете что-то, что потом не сможете ни объяснить, ни поддержать, ни модифицировать.

Идея


Норвежская компания Trolltech AG (изначально называвшаяся Quasar Technologies, откуда, собственно, и пошла аббревиатура Qt) образовалась из двух (хм…) норвежцев, Эйрика Енга (Eirik Eng) и Хаварда Норта (Haavard Nort) с целью… короче, как всегда, с целью подрубить бабла. Но, кроме того, еще и создать пару нетленок из разряда универсальных библиотек, которые завоюют весь мир. Уж такой народ норвежцы — не могут без славы и денег.

Дело было в 1994 г. в городе Осло. Само сочетание "Qt" некоторые произносят как "кьют" ака cute — то есть "мило, прикольно". В общем-то, так оно и есть, если, конечно, вы способны оценить красоту, выраженную в терминах С++.

Говоря более конкретно, во главу угла были поставлены две вещи. Первое: библиотеки создавались для языка С++. Второе: основой всему был именно интерфейс пользователя, поскольку это самый несовместимый и позорный момент во всем софтвере — полностью разные парадигмы графического пользовательского интерфейса.

Как известно, MS Windows использует "локальный" GUI API, который, однако, недавно был транспонирован на сетевые подключения в XP Remoting. Все UNIX-like, и Linux в том числе, были изначально (ну, как изначально — как только рабочие станции доросли до графики, естественно) завязаны на X Windows, который, хоть и работает от рождения по сети, но локально показывает худшие характеристики быстродействия и реактивности из всех рассматриваемых интерфейсов. Наконец, графика Mac OS, зашитая полуаппаратно в фирменных BIOS-"тулбоксах", всегда показывала скорость и красоту, даже когда Windows еще под стол пешком ходила. Но это было: а) проприетарно, б) ни с чем не совместимо — даже приблизительно.

Короче — бардак и брожение умов. Вот прибалты и задумались…

Точнее задумались-то не только они. В качестве переносимого графического интерфейса можно использовать хоть Java, хоть Tk/Tcl, а хоть и Macromedia Flash — на последних версиях этого Flash можно писать вполне приличные приложения. Это только те "задумавшиеся", у кого получилось,— об остальных мы просто не знаем.

Да, так вот, у Trolltech тоже неплохо получилось, как именно — сейчас посмотрим.

Инсталл


Конечно же, сначала следует проинсталлировать систему. Под Windows нужно обратить внимание на три вещи. Во-первых, потребуется ввести имя пользователя, компанию и сериал. Вводите их точно в таком же виде, как указано в письме, которое вам придет (сериал является хеш-фанкшином от даты активации и двух остальных полей) — иначе ничего работать не будет.

Во-вторых, при инсталляции предпоследним пунктом идет установка примеров. Они приходят в виде исходных текстов, но в процессе установки будут компилироваться. Компиляция происходит в командной строке, так что без установленных переменных окружения это не сработает, получите ошибку "где линкер дел, гад?". Пофиксить проблему просто: создайте и запустите bat-файл типа: call "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat" qt-win-eval-msvc-3.3.3.exe

Третья заморочка: примеры и туторы тоже так просто работать не станут. Они не могут найти свою библиотеку, хотя в переменной пути к ней все вроде и указано. На самом деле для правильной работы нужно установить переменные окружения — а они, в свою очередь, устанавливаются при загрузке профиля пользователя. Даже и перезагружаться не нужно, просто отлогоньтесь-прилогоньтесь. Кстати, о необходимости такой операции пишется в конце инсталляции — но кто же такое читает?

Если вы инсталлируетесь под Linux и BSD, то я вам ничего не стану рассказывать — сами с ушами. Скажу только, что уровень проблем при инсталляции под этой ОС может колебаться в очень больших пределах, в зависимости от поддержки вашего дистрибутива и его "комплектации" на момент установки. Я ставил на Slakware, RH и Mandrake без особых проблем. В любом случае Qt нужно ставить на KDE.

Интеграция


Это, конечно, не бог весть что, но, тем не менее, приятно и весьма полезно — Qt во время инсталляции интегрируется в Visual Studio, так что вы сможете добавлять потом новые проекты, формы и т.д. прямо из дополнительной панельки. Кроме того, там доступно быстрое переключение на подсказку в QtAssistant — раз уж вся среда не зависит от платформы, было бы просто позором сделать справку по ее системе. В результате html’ные "хелпы" от Microsoft тут нет — вместо них используются похожие, но собственного формата и, естественно, с оболочкой на самом Qt.

Qt также хорошо интегрируется в Visual Studio, хотя это и не совсем то, для чего он создавался

Как оно работает


Говоря в общем, все вращается вокруг событий, называемых сигналами, и слотов — то есть регистрируемых реакций на эти события. В отличие от других "закрытых" событийных множеств (вроде тех, что встречаются в Active Script) система сигналов Qt полностью динамическая — каждый участок кода может регистрировать или обрабатывать сигналы. Это напоминает механизм, условно известный как WM_USER+1.

Сигналы имеют отдаленное отношение к системным событиям и являются их произвольной трансляцией — так же как это реализовано в Delphi. Естественно, что ни одна система не должна порождать таких шквалов нотификаций, как Windows. Обеспечивать приложению доступ к событиям неклиентской области — по-моему, большая ошибка архитекторов этой системы, породившая немало "смешных" интерфейсов.

Что касается графического интерфейса, то он более всего похож на Java Swing — тут тоже существуют схемы стилей, например Windows, CDE, Motif, копирующие известные оболочки. Присутствуют также layout’ы, автоматически размещающие элементы управления; кроме того, есть такие "пружинки", или "спейсеры", которые расталкивают сопредельные компоненты.

Есть также немало вещей, напоминающих Delphi: хинты размеров (то есть "как было бы лучше"), масштабирование компонент и прочие вещи, претендующие на красивость.

Как и в Swing, все элементы перерисованы от руки, то есть стандартные механизмы рисования элементов управления не применяются — вместо этого используется, например, GDI WinAPI. Автоматически определяется версия ОС и, соответственно, реализуются или игнорируются те или иные свойства, вроде прозрачности или XP-прибамбасов. В качестве небольшого попуска Qt использует стандартные диалоговые окна Windows, в частности диалоги открытия файла и настойки печати.

Под X11 Qt не использует тулкиты вроде Motif или Xt — ну, Qt вроде и сам такой же тулкит (то есть — зачем же?). Вместо этого напрямую используется Xlib — с расширениями вроде RENDER, если они доступны.

Схема "генеральной помпы", то есть основного цикла событий, не очень отличается от всех подобных во всех ОС — от MS Windows до PalmOS.
Приложение строится просто, если не сказать примитивно: создается главное окно, устанавливаются его параметры, после чего приложение непосредственно "ранится". Вот как выглядит известный всем "Привет, мир!": #include < qapplication.h >
#include < qlabel.h >
int main( int argc, char **argv )
{
QApplication app( argc, argv );
   QLabel *hello = new QLabel( "Привет, мир!", 0 );
   app.setMainWidget( hello );
   hello->show();
   return app.exec();
} Естественно, это вам не Visual Basic: вы можете создавать собственные элементы управления — это, как и в Delphi, поощряется, а не наоборот. Писать их не сложнее, чем дельфийские, а то и проще. Вот, к примеру, как реализуются LCD-часы на основе класса, отрисовывающего LCD-строку: #include < qdatetime.h >
#include "clock.h"
Clock::Clock( QWidget *parent, const char *name )
: QLCDNumber( parent, name ), showingColon( true ) {
   showTime();
   startTimer( 1000 );
}
void Clock::timerEvent( QTimerEvent * ) { showTime(); }
void Clock::showTime() {
   QString time = QTime::currentTime().toString().left( 5 );
   if ( !showingColon ) time[2] = ’ ’;
   display( time );
   showingColon = !showingColon;
} Не сложно — а если б выключить мигание двух точек, так и вовсе тривиально. Кстати, мне показалось что знак "!" перед showingColon можно "сэкономить" — ну, конечно, заменив для мнемоничности showcolon на hidecolon. Да и showTime() в конструкторе можно бы убрать… Короче, в полном ходу лозунг Trolltech: code_less && create_more — только не стоит вычислять эту выражение по короткой схеме :).

Кю-тэшное семейство, обзор


На самом деле существует несколько продуктов Qt, хотя все они "завязаны" на одном и том же коде. Собственно Qt — это межплатформенная библиотека для С++. Более конкретно — библиотека классов, "цешники"-натуралы отдыхают. То есть это даже и библиотекой-то не назовешь — сами создатели именуют это как framework, то есть программная оболочка. Но, конечно, от этого она не перестает быть обычной библиотекой.

Применение нового "стиля" в Qt может мгновенно придать вашему приложению новый вид

Помимо переносимого интерфейса библиотека также занимается интернационализацией, то есть располагает инструментом для перевода интерфейса на ваш родной китайский язык (сделано это, кстати, очень прикольно). Менеджер релизов выкусывает из кода все строки, подлежащие переводу. Они должны быть, правда, особого формата, чтоб не было накладок с непереводимыми фразами. Короче, полученные таблицы фраз поступают в средство перевода — Linguist. Сам он ничего не переводит (это делаете вы) — но зато помогает сохранять уже переведенные фразы в словарях. Так что вы можете менять программу как вам угодно, и то, что уже переведено, уже никогда не будет требовать перевода.

Третье, что было сделано (кстати, уже по ходу разработки — по просьбе многих клиентов), это системно-независимые механизмы доступа к базам данных. Конечно, я уже не говорю о таких вещах, как унифицированный сетевой доступ, XML, трехмерная графика и так далее — просто различия в этих сферах не так разительны, как в перечисленных выше.

Выходит, что Qt — это как бы "мегапатч" к стареньким си-либам, позволяющий: работать в графике; переводить программы; выполнять запросы к БД; унифицированно реализовывать все остальное, вроде мультимедиа.

Помимо основной библиотеки, существует основанный на том же коде framework для всякой мобильной живности вроде смарт-фонов и PDA под управлением Embedded Linux (особенно засветился в этом секторе Sharp). Называется эта штуковина Qtopia. Инструмент для разработки встроенных систем с ограниченной функциональностью называется Qt/Embedded.

Далее, QSA — скриптовый язык, позволяющий управлять готовыми приложениями на Qt/C и расширять их возможности в скриптовом контексте.

Teambuilder — средство компиляции, которое собирает статистику утилизации CPU по целой рабочей группе и позволяет оптимизировать процесс сборки на менее загруженных станциях.

Ко всему, существует несколько "плугов" для известных сред разработки (говоря проще — для Visual Studio и Borland Builder), упрощающих разработку под Qt,— Qt Solutions.

В качестве визуального инструмента разработки используется Qt Designer — это "малевалка" интерфейса, подобная всем "клик-энд-го". Конечно, еще полно полезного хелпняка: просто тысячи артиклов, плюс девяносто шесть (проверьте) примеров — и это есть гуд.

Однако сосредоточимся на Qt — все остальное вторично.

QT: интерфейс, и не только...


Арсений Чеботарев,

Если вы связаны с программированием, то наверняка уже встречали сочетание Qt. Многие (0,1%) из вас даже использовали Qt в своих разработках, пусть даже как следствие инсталляции Borland Kylix. В общем, самое время посмотреть на Qt, что называется, "в упор, двумя глазами"…

Этот продукт на слуху у всех разработчиков, которые программируют для Linux. И не только у них — например, самый модный и удобный многоплатформенный клиент для сетей AIM/ICQ (точнее, ICQ/AIM), sim, написанный питерцем Володей Шутовым, создан именно с использованием Qt. Не говоря уже о Borland Kylix — там вообще все работает поверх Qt.

Такие совпадения — там вилочка, тут ножичек — поневоле задумаешься…

Адаптация средств инструмента CTesK к предложенной схеме тестового набора


В используемом тестовом стенде у инструментального и целевого узла имеется по одному сетевому интерфейсу, которые соединены кросс-кабелем, поэтому пакеты в процессе доставки не перемешиваются. Поскольку в большинстве случаев обмены сообщениями между мобильным узлом и демонами являются синхронными, порядок поступления сообщений может изменяться лишь в том случае, если два сообщения отправляются одним и тем же узлом и являются частью разных параллельно выполняющихся процедур обмена сообщениями. Стандарт RFC 3775 не накладывает никаких ограничений на связь между параллельно выполняющимися процедурами, поэтому такое нарушение порядка не может повлиять на выносимый тестовым сценарием вердикт. Это позволяет в разрабатываемом тестовом наборе не использовать сериализацию. Точнее, при сериализации рассматривается лишь один порядок поступления стимулов и реакций.

В выбранной модели тестирования используются две группы стимулов: стимулы, действующие на виртуальную сеть, и стимулы, действующие на тестируемую реализацию. Сбор пакетов не приостанавливается между вызовами сценарных функций, поэтому пакеты, собранные за время обработки результатов вызова сценарной функции, будут рассматриваться после вызова следующей сценарной функции. Это означает, что отключение сериализации приводит к нарушению порядка поступления стимулов. Однако порядок вызова стимулов, воздействующих на тестируемую реализацию, будет сохраняться, а стимулы, воздействующие на сеть, не изменяют структур данных, имитирующих состояние тестируемой реализации. Поэтому такое нарушение порядка поступления стимулов не повлияет на вердикт, выносимый спецификациями.

Стандарт RFC 3775 представляет собой обычный текст, из которого можно выделить несколько сотен четких требований. При построении формальных спецификаций в виде пред- и постусловий для сообщений от тестируемой реализации может оказаться, что некоторые постусловия содержат проверку для десятков требований стандарта. Инструмент CTesK в случае нарушения одного из таких требований выдаст немногословный вердикт false.
Однако по сообщению, на котором был выдан такой вердикт, не всегда просто понять, какое же именно требование стандарта было нарушено. Чтобы решить эту проблему, введена вспомогательная функция conformance_check, осуществляющая проверку требования стандарта и сбрасывающая в тестовую трассу информацию о результате его проверки, а также о ситуации, в которой эта проверка производилась. По такой информации впоследствии генерируется детальный отчет о проверенных требованиях стандарта. Элементарной реакцией от целевой системы в рассматриваемой модели тестирования является пакет, но многие требования стандарта применяются не ко всему пакету, а к отдельным его заголовкам. Проверку таких требований в инструменте CTesK принято осуществлять в инвариантах типов данных, описывающих заголовки пакета. Однако в тестовом наборе используются одни и те же типы данных для заголовков, содержащихся в пакетах от мобильного узла и в пакетах от демонов. Проверка же должна производится только для пакетов от мобильного узла, так как некорректно построенные заголовки в пакетах от демонов допускаются и используются при тестировании внештатных ситуаций. Поэтому проверка таких требований вынесена за пределы спецификационной функции и происходит еще до регистрации реакций на этапе разбора пакета по заголовкам. Для идентификации пакета в отчете удобно использовать время, когда был получен пакет. Время получения передается стимулам и реакциям вместе с другой информацией о пакете через аргумент спецификационной функции или реакции соответственно. Однако инструмент CTesK не позволяет использовать в предусловии значение аргумента передаваемого реакции, поэтому проверку всех требований пришлось вынести в постусловие реакций. Следует также отметить, что отчеты, которые может генерировать инструмент CTesК, в данной работе не используются. Вместо этого, отчет о проведенном тестировании генерируется отдельной частью тестового набора по тестовой трассе и нескольким вспомогательным файлам. Такие отчеты ориентированы на конкретную задачу, более наглядны и понятны пользователю, не знакомому с технологией UniTESK.

Аннотация.


Статья посвящена разработке тестового набора для проверки соответствий реализаций мобильного узла спецификациям протокола Mobile IPv6 []. Для построения тестового набора использовались передовая технология автоматического тестирования UniTESK [] и инструмент CTesK [], разработанный на основе этой технологии. В ходе выполнения работы было выявлено несколько особенностей поведения одного из объектов протокола - мобильного узла, которые затрудняют его тестирование в рамках указанной технологии. В статье подробно описаны эти особенности и способы преодоления трудных моментов в условиях ограничений технологии UniTESK и поддерживающего эту технологию инструмента CTesK. Работа выполнялась в Институте системного программирования РАН в рамках проекта «Верификация функций безопасности и мобильности протоколов IP» при поддержке гранта РФФИ № 04-07-90308.



Апробация разработанного тестового набора


При помощи разработанного тестового набора было проведено тестирование открытой реализации Mobile IPv6 KAME для операционной системы FreeBSD 5.4 (CVS Snapshot 2006.11.13). Во время проведения тестирования эта реализация была одной из наиболее распространенных открытых реализаций Mobile IPv6.

При прогоне тестовых сценариев был выявлен ряд нарушений требований стандарта RFC 3775 [], например: мобильный узел выполняет процедуру Duplicate Address Detection не во всех случаях, когда это необходимо; мобильный узел при смене точки подключения не всегда производит регистрацию основного временного адреса на домашнем агенте; мобильный узел нарушает ограничения темпа отправления сообщений Binding Update; мобильный узел не соблюдает некоторые рекомендации процедуры Generic Movement Detection; мобильный узел не всегда использует корректные значения для времени ожидания ответа на такие сообщения, как Binding Update, Home Test Init, Care-of Test Init, Mobile Prefix Solicitation.

Помимо этого, в некоторых случаях поведение тестируемого мобильного узла было заведомо некорректным, например, некоторые сообщения отправлялись на неправильный адрес канального уровня. Кроме того, исполнение некоторых тестовых сценариев приводило к зависанию или перезагрузке мобильного узла, что свидетельствует о нестабильности целевой реализации. Результаты проведенного тестирования с указанием нарушенных требований стандарта доступны по этому адресу.

Инструмент CTesK


Для построения тестового набора в данной работе использовался инструмент CTesK, который позволяет эффективно распараллелить разработку тестового набора и автоматизировать разработку тестовых сценариев. Ниже приведено краткое описание возможностей этого инструмента и обзор технологии UniTESK, которую он реализует.

В инструменте CTesK объектом тестирования является целевая система. У этой системы имеется набор интерфейсов, с помощью которых она взаимодействует с окружением. Набор этих интерфейсов изначально определен и специфицирован. Все требования, которые предъявляются к системе, накладываются на наблюдаемые действия системы, которые можно отследить через интерфейсы ее взаимодействия с окружением. Эти требования не затрагивают внутренней реализации системы, т.е. тестирование производится по принципу «черного ящика».

При использовании инструмента CTesK требования, предъявляемые к целевой системе, должны быть описаны на формальном языке SeC, который является спецификационным расширением языка C. Впоследствии из таких требований автоматически генерируется исполняемый код, который используется в процессе тестирования.

Взаимодействие с целевой системой осуществляется при помощи стимулов и реакций. Стимулами называются средства, при помощи которых можно передавать целевой системе какую-либо информацию. Целевая система может непосредственно возвращать некоторый ответ на стимул, а также изменять свое внутреннее состояние. Такой ответ и изменение состояния, если имеется доступ к состоянию системы, возвращаются в тестовую систему, и производится проверка соответствия поведения системы наложенным на нее требованиям. Требования описываются на формальном языке в виде постусловий. Для стимулов в виде предусловия описываются ограничения, при которых можно вызывать данный стимул. Дополнительно могут накладываться ограничения на возможные значения данных определенного типа в виде инвариантов.

Некоторые следствия работы системы и результаты воздействия на нее определенных стимулов могут наблюдаться не сразу, а после завершения внутренних процессов.
Такое поведение приводит к тому, что реакция на стимул поступает наружу через какое-то время после воздействия на систему одного или нескольких стимулов, или может даже проявляться без воздействия стимулов на систему. Такую информацию не во всех случаях можно охарактеризовать как ответ на какой-либо стимул, и она называется реакцией (отложенной реакцией) системы. На реакции системы обычно также накладывается ряд требований. Аналогично случаю со стимулами, в инструменте CTesK они описываются в виде пред- и постусловий. Предусловия определяют ограничения на состояния системы, при которых может происходить данная реакция. А постусловия описывают ограничения на саму реакцию, то есть на данные, которые передаются окружению при помощи этой реакции, и на изменение состояния целевой системы, которое может происходить при возникновении такой реакции. Для описания требований к стимулам и реакциям тестовый набор должен обладать информацией о состоянии целевой системы и о его изменениях. Для этого тестовым набором поддерживаются структуры данных, моделирующие это состояние. Далее состояние этих структур данных будет называться модельным состоянием. Если имеется доступ к внутренним структурам данных целевой системы, описывающих это состояние, то возможна синхронизация состояния модели и целевой системы. В таком случае возможна проверка требований, касающихся изменения состояния внутренних структур данных. В противном случае состояние модели и состояние целевой системы изменяются независимо и синхронизируются лишь на начальном этапе тестирования. При этом требования накладываются только на действия системы, наблюдаемые извне. Нарушение требований обработки внутренних структур данных проверяются лишь неявно при последующих некорректных ответах на стимулы и возникновении некорректных реакций. Тестовый набор, разрабатываемый при помощи инструмента CTesK, может быть ориентирован не на конкретную целевую систему, а на группу целевых систем, поведение которых описывается одними и теми же требованиями.


Причем некоторые целевые реализации могут предоставлять доступ к внутренним структурам данных, а другие нет. Для обеспечения универсальности в тестовый набор включается специальная часть, которая называется медиатором. Для каждого отдельного стимула медиатор осуществляет преобразование данных из модельного представления тестового набора в представление целевой системы, а для каждой реакции выполняет обратное преобразование. Таким образом, медиатор зависит от конкретной целевой системы. Поэтому, для того чтобы произвести тестирование новой целевой системы, необходимо заново разработать для нее медиаторы. Вся информация о ходе тестирования сохраняется в специальном файле, который называется тестовой трассой. По данным, которые содержатся в этом файле, генерируется отчет об ошибках и покрытии. Трасса хранится в формате XML, что позволяет легко разрабатывать средства для ее анализа. В инструменте CTesK имеются средства для автоматического измерения тестового покрытия. Для этого в описание стимула добавляется специальный блок coverage, в котором, исходя из модельного состояния и параметров вызова стимула, определяется, какую из ветвей функциональности целевой системы задействует данный стимул. Инструмент CTesK включает в себя утилиту, которая после завершения тестирования по информации, содержащейся в тестовой трассе, генерирует подробную статистику и отчет о тестовом покрытии. Стимулы и реакции на языке SeC описываются в виде спецификационных функций. Для стимула такая спецификационная функция включает в себя предусловие, постусловие и блок coverage. Для реакции - только предусловие и постусловие. Для каждой спецификационной функции разрабатывается медиатор, который оформляется в виде функции. Медиатор для стимула имеет два блока: блок call, который отвечает за передачу соответствующего стимула реализации и за получение результата, и блок state, который отвечает за обновление модельного состояния. Для реакции медиатор содержит только блок state, который выполняет аналогичную функцию. В инструменте CTesK термин тестовый сценарий используется для обозначения группы тестовых операций, обычно предназначаемых для тестирования логически связанных аспектов функциональности целевой системы.


Если в ходе исполнения тестового сценария обнаруживается ошибка, то тестовый сценарий завершается. Такая мера является вынужденной, так как после возникновения ошибки состояния тестового набора и целевой системы оказываются не синхронизированными. Выполнение тестового сценария заключается в вызовах сценарных функций. Сценарная функция содержит исполняемый код и вызовы стимулов. В ходе выполнения сценарной функции собираются реакции от системы (см. Рис. 4). После завершения сценарной функции запускается механизм, называемый сериализацией. В процессе сериализации перебираются возможные порядки вызовов стимулов и наступления реакций (см. Рис. 5). Чтобы поведение целевой системы могло считаться корректным, требуется, чтобы хотя бы один из порядков удовлетворял требованиям в виде пред- и постусловий стимулов и реакций.

Рис. 4. Исполнение сценарной функции

Рис. 5. Один из сценариев сериализации В процессе проверки одного из порядков сериализации тестовый сценарий может проходить через последовательность состояний модели. Такие промежуточные состояния называются нестационарными. Вызов сценарной функции должен обязательно закончиться в стационарном состоянии, иначе поведение целевой системы является некорректным. Кроме того, все допустимые последовательности сериализации, которые заканчиваются в стационарном состоянии, должны приводить к одному и тому же состоянию. Иначе выполнение тестового сценария будет прервано с сообщением об ошибке. В функциях, выполняющих сериализацию, используются методы сохранения состояния модели, восстановления состояния модели, а также определения, является ли данное состояние стационарным. Если имеется информация о частичном порядке вызовов стимулов и поступления реакций, то можно существенно сократить процесс сериализации по сравнению с полным перебором или даже свести ее к рассмотрению одного единственного варианта. В инструменте CTesK предусмотрены средства для разбиения множества модельных состояний на группы. Такое разбиение называется факторизацией состояний, а полученные обобщенные состояния - состояниями тестового сценария.


На выбор факторизации накладывается следующее ограничение: после вызова определенной сценарной функции из определенного начального состояния тестового сценария тестовый сценарий всегда должен перейти в одно и то же конечное состояние. Пример факторизации модельных состояний схематично представлен на Рис. 6.
Рис. 6. Переходы в модельных состояниях и состояниях тестового сценария Для осуществления факторизации разработчик должен предоставить тестовому сценарию функцию, которая по текущему модельному состоянию возвращает состояние тестового сценария. При разработке тестового сценария разработчик определяет начальное модельное состояние и набор сценарных функций. Тестовый сценарий автоматически выбирает порядок вызовов сценарных функций. Такую функциональность осуществляет компонент под названием обходчик. Обходчик перебирает вызовы всех возможных сценарных функций во всех достижимых состояниях тестового сценария. Это осуществляется при помощи обхода графа, вершинам которого соответствуют состояния тестового сценария, а дугам - переходы по вызовам сценарных функций. Такой граф задается для тестового сценария неизбыточным образом путем указания начального состояния тестового сценария, набора сценарных функций и функции, определяющей состояние тестового сценария после выполнения сценарной функции. Инструмент CTesK включает в себя два обходчика: dfsm [], который реализует обход в глубину графа состояний тестового сценария, и ndfsm [], использующий жадный алгоритм для выбора ближайшей вершины, в которой применялись не все возможные воздействия. На практике второй обходчик оказывается более эффективным, поэтому он и использовался в разрабатываемом тестовом наборе. Для корректной работы обоих обходчиков граф состояний тестового сценария должен удовлетворять требованиям связности и детерминированности. Связность в данном случае может формулироваться следующим образом: из любого состояния тестового сценария, в которое можно попасть из начального состояния при помощи последовательности вызовов сценарных функций, можно вернуться в начальное состояние при помощи последовательности вызовов сценарных функций.


Условие детерминированности означает, что при вызове одной и той же сценарной функции из одного и того же состояния тестового сценария мы всегда попадаем в одно и тоже конечное состояние тестового сценария. Обходчик в своей работе может пользоваться компонентом под названием итератор. Итератор используется, если в сценарной функции на разных этапах ее запуска необходимо вызывать стимулы с различными параметрами. Такую функциональность можно осуществить при помощи написания отдельной сценарной функции для каждой группы параметров, но в таком случае может понадобиться очень большое количество сценарных функций. В языке SeС используется специальная конструкция iterate для перебора параметров стимула. Синтаксис этой конструкции напоминает синтаксис оператора цикла for. Счетчик цикла для этой конструкции называется счетчиком итерации. Таким образом, когда обходчик встречает в коде сценарной функции такую синтаксическую конструкцию, он вызывает итератор. Итератор возвращает значения счетчиков итерации для вызова данной сценарной функции так, чтобы в каждом состоянии тестового сценария осуществлялся перебор всех возможных наборов счетчиков итерации. С использованием итератора обходчик вызывает все сценарные функции со всеми возможными значениями счетчиков итерации во всех достижимых состояниях тестового сценария. Такая автоматизация существенно упрощает разработку тестового сценария.

Литература


1.обратноD. Johnson, C. Perkins, J. Arkko "Mobility Support in IPv6", RFC 3775, June 2004.
2.обратноСайт, посвященный технологии тестирования UniTESK и реализующим ее инструментам.
3.обратноСтраница инструмента CTesK.
4.обратноS. Deering, R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", RFC 2460, December 1998.
5.обратноS. Thomson, T. Narten, "IPv6 Stateless Address Autoconfiguration", RFC 2462, December 1998.
6.обратноT. Narten, T. Nordmark, E. and W. Simpson, "Neighbor Discovery for IP Version 6 (IPv6)", RFC 2461, December 1998.
7.обратноA. Conta, S. Deering "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification", RFC 2463, December 1998.
8.обратноИ. Б. Бурдонов, А. С. Косачев, В. В. Кулямин. Неизбыточные алгоритмы обхода ориентированных графов: детерминированный случай. Программирование, т. 29, № 5, стр. 59-69, 2003.
9.обратноА. В. Хорошилов. Отчет о научно-исследовательской работе. Алгоритмы обхода недетерминированных графов, обладающих детерминированным полным остовным подграфом.
10.обратноBertrand Meyer. Object-Oriented Software Construction, Second Edition. Prentice Hall, 1997.
11.обратноS. Bradner, "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.



Данный раздел является кратким введением


Данный раздел является кратким введением в протокол Mobile IPv6. Как уже отмечалось, этот протокол является расширением протокола нового поколения IPv6, которое позволяет узлу, совершающему перемещения по сети Интернет, все время оставаться доступным по адресу, который он имел в первоначальной (домашней) сети. Такая возможность позволяет избежать потери соединений транспортного уровня при перемещениях межсетевого уровня модели TCP/IP, а также дает возможность другим узлам устанавливать соединение с мобильным узлом (Mobile Node) в то время, когда он находится за пределами домашней сети. Для простоты мы будем рассматривать случай, когда у мобильного узла есть только один домашний адрес. Поведение мобильного узла в случае нескольких домашних адресов можно считать аналогичным. Когда мобильный узел находится в домашней сети, никакой дополнительной функциональности от узлов, участвующих во взаимодействии, не требуется, и мобильный узел ведет себя как обычный IPv6-узел (см. Рис. 1). Когда мобильный узел переходит в сеть, которая обслуживается другими маршрутизаторами и имеет другие сетевые префиксы, без дополнительной поддержки со стороны Mobile IPv6 узел становится недоступным по своему домашнему адресу. Пакеты, отправляемые ему другими узлами, будут по-прежнему приходить в домашнюю сеть и не будут доходить до мобильного узла. Это приведет к потере установленных соединений. Рис. 1.Мобильный узел в домашней сети Для того чтобы этого не происходило, в протоколе Mobile IPv6 вводится специальный вид маршрутизаторов, которые называются домашними агентами (Home Agents). Домашний агент (см. Рис. 2) всегда находится в домашней сети и осуществляет переадресацию пакетов мобильному узлу в то время, когда последний находится за пределами домашней сети. Это осуществляется при помощи механизма, который называется двусторонним туннелированием (Bi-directional Tunneling). Рис. 2. Мобильный узел вне дома Структура IPv6-пакета подробно описана в RFC 2460 []. Однако здесь следует отметить, что в протоколе IPv6 в пакет могут добавляться заголовки расширения, которые содержат некоторую дополнительную информацию о том, как этот пакет должен обрабатываться конечным получателем или промежуточными узлами сети.
Заголовки расширения связаны в односвязный список при помощи поля Next Header, которое содержится во всех заголовках уровня IP. Поле Next Header последнего заголовка расширения IPv6-пакета указывает на протокол транспортного уровня, сегмент которого передается в качестве полезной нагрузки. Каждый из заголовков расширения имеет фиксированную часть, которая всегда должна присутствовать в заголовке данного типа, и может содержать дополнительную часть в виде опций. Опции располагаются в конце заголовка и описываются в представлении TLV (Type-Length-Value). Когда мобильный узел попадает во внешнюю сеть, он формирует один или несколько временных адресов (Care-of Addresses) согласно механизму автоматической конфигурации адресов [], который используется во внешней сети. После этого мобильный узел выбирает один из своих временных адресов и сообщает его домашнему агенту; такой адрес называется основным временным адресом (Primary Care-of Address). Это осуществляется при помощи процедуры, которая называется регистрацией основного временного адреса (Primary Care-of Address Registration). Для этого мобильный узел отправляет домашнему агенту служебное сообщение Binding Update со своего основного временного адреса. В этом сообщении мобильный узел при помощи заголовка расширения Destination Options, содержащего опцию Home Address, указывает свой домашний адрес, для которого выполняется данная процедура. В ответ на сообщение Binding Update домашний агент отправляет служебное сообщение Binding Acknowledgement, которое либо свидетельствует о том, что сообщение Binding Update принято, либо указывает причину, по которой оно было отклонено. Для обеспечения безопасности такого обмена сообщениями используются средства протокола IPsec. Перед отправлением сообщения Binding Acknowledgement домашний агент запоминает связь между домашним адресом мобильного узла и его основным временным адресом в структуре данных, которая носит название кэш привязок (Binding Cache), а сама связь называется привязкой (binding). После установления привязки домашний агент начинает перехватывать пакеты, которые приходят на домашний адрес мобильного узла, и через IPv6-туннель пересылать их мобильному узлу на его основной временный адрес. Такой перехват пакетов, направленных мобильному узлу, осуществляется при помощи механизма, называемого Proxy Neighbor Discovery.


Суть этого механизма заключается в том, что домашний агент отправляет необходимые сообщения Neighbor Advertisement, используемые в механизмах Address Resolution и Neighbor Unreachability Detection, от имени мобильного узла, но со своим адресом канального уровня. Таким образом, мобильный узел, находясь в чужой сети, через IPv6-туннель с домашним агентом, получает сообщения, которые отправляются ему в домашнюю сеть. Мобильный узел, в свою очередь, поддерживает структуру данных, которая называется Binding Update List. В этой структуре данных содержится информация обо всех привязках и об их состоянии. Перед отправлением пакета в сеть мобильный узел просматривает Binding Update List. Если там есть привязка, для которой зарегистрированный домашний адрес совпадает с адресом отправителя пакета (Source Address), то пакет отправляется не напрямую, а через IPv6-туннель с домашним агентом, указанным в привязке. Домашний агент, получив из IPv6-туннеля такой пакет, отправляет его из домашней сети по обычному маршруту. Таким образом, мобильный узел всегда остается доступным по своему домашнему адресу. Узел, с которым мобильный узел обменивается сообщениями, называется узлом-корреспондентом (Correspondent Node). Для обмена информацией с мобильным узлом при помощи двустороннего туннелирования от узла-корреспондента требуется лишь поддержка базовой функциональности IPv6. Дополнительной поддержки Mobile IPv6 от узла-корреспондента в этом случае не требуется. Однако двустороннее туннелирование создает дополнительный обмен сообщениями и дополнительную нагрузку на домашнего агента. Протокол Mobile IPv6 позволяет этого избежать и производить обмен информацией напрямую (не через домашнюю сеть), если узел-корреспондент поддерживает дополнительную функциональность Mobile IPv6, которая называется оптимизацией маршрута (Route Optimization). Узел-корреспондент, поддерживающий оптимизацию маршрута, так же как и домашний агент, имеет кэш привязок, в котором содержится информация о привязках с мобильными узлами и об их состояниях.


У мобильного узла, в свою очередь, в структуре Binding Update List содержится информация о привязках с узлами-корреспондентами. Перед отправлением в сеть пакета, у которого адрес отправителя совпадает с домашним адресом, мобильный узел просматривает Binding Update List, и если находит привязку с узлом-корреспондентом, адрес которого совпадает с адресом получателя пакета, то пакет отправляется напрямую. При этом в качестве адреса отправителя пакета указывается временный адрес, а в сообщение добавляется заголовок расширения Destination Options, который содержит опцию Home Address с домашним адресом мобильного узла. Если же такой привязки нет, то мобильный узел ищет привязку с домашним агентом и отправляет пакет через туннель домашнему агенту, который пересылает его узлу-корреспонденту. При получении пакета с опцией Home Address узел-корреспондент ищет в кэше привязок запись, у которой временный адрес совпадает с адресом отправителя, указанным в пакете, а домашний адрес совпадает с адресом, указанным в опции Home Address. Если такая привязка находится, то узел-корреспондент меняет местами адрес отправителя пакета и адрес, указанный в опции Home Address; затем пакет передается на дальнейшую обработку. При отправлении пакета в сеть узел-корреспондент просматривает кэш привязок и ищет там привязку, у которой домашний адрес мобильного узла совпадает с адресом получателя пакета (Destination Address). Если такая привязка находится, то узел-корреспондент подставляет временный адрес, указанный в привязке, вместо адреса получателя, и в пакет добавляется заголовок расширения Routing Header Type 2, в котором указывается домашний адрес мобильного узла. При получении такого пакета мобильный узел проверяет, что адрес, указанный в заголовке Routing Header Type 2, является его домашним адресом, и меняет местами адрес получателя пакета с адресом, указанным в данном заголовке. Затем пакет передается на дальнейшую обработку. Такой механизм обмена сообщениями между мобильным узлом и узлом-корреспондентом (см.


Рис. 2) является прозрачным для протоколов верхнего уровня и носит название оптимизации маршрута. Механизм установления привязки с узлом-корреспондентом аналогичен механизму установления привязки с домашним агентом. Для этого мобильный узел отправляет сообщение Binding Update узлу-корреспонденту, в котором содержатся домашний и временный адрес. В некоторых случаях узел-корреспондент должен отправить в ответ сообщение Binding Acknowledgement, подтверждающее установление привязки, хотя обычно этого не требуется. Для обеспечения безопасности механизма установления привязки с узлом-корреспондентом в сообщения Binding Update и Binding Acknowledgement добавляется опция Binding Authorization Data, которая содержит криптографическую хэш-сумму этих сообщений. Хэш-сумма вычисляется по алгоритму HMAC_SHA1 с использованием ключа управления привязкой (Kbm), который генерируется перед обменом сообщениями Binding Update и Binding Acknowledgement при помощи процедуры обратной маршрутизируемости (Return Routability Procedure).
Рис. 3. Процедура обратной маршрутизируемости (return routability procedure) Процедура обратной маршрутизируемости выполняется с целью аутентификации узла-корреспондента. Для этого обмен сообщениями с узлом-корреспондентом производится по двум маршрутам: напрямую и через домашнюю сеть (см. Рис. 3). А именно, мобильный узел посылает со своего временного адреса сообщение Home Test Init через туннель с домашним агентом, а сообщение Care-of Test Init - напрямую. В ответ на эти сообщения узел-корреспондент посылает сообщения Home Test на домашний адрес и Care-of Test на временный адрес мобильного узла; эти сообщения содержат маркеры home keygen token и care-of keygen token соответственно. При помощи этих маркеров и генерируется ключ управления привязкой (Kbm). Протокол Mobile IPv6 включает в себя несколько вспомогательных служебных процедур обмена сообщениями для мобильного узла: Generic Movement Detection, Dynamic Home Agent Address Discovery и Mobile Prefix Discovery.Эти процедуры используют сообщения протокола ICMPv6. Процедура Generic Movement Detection позволяет отследить перемещение мобильного узла при помощи средств протокола Neighbor Discovery []. Для двух оставшихся процедур вводятся четыре новых типа сообщений протокола ICMPv6 []. Процедура Dynamic Home Agent Address Discovery позволяет узнать адрес домашнего агента в то время, когда мобильный узел находится за пределами домашней сети. Процедура Mobile Prefix Discovery позволяет мобильному узлу узнать об изменении префиксов в домашней сети в то время, когда мобильный узел находится за ее пределами, и, тем самым, принимать участие в смене префиксов домашней сети (Network Renumbering).

Труды Института системного программирования


Зацепин Д.В., Шнитман В.З.,
Труды Института системного программирования РАН

Проблемы тестирования мобильного узла и способы их решения


Реализация функциональности мобильного узла интегрируется в IPv6-стек, и воздействовать на нее можно двумя способами: при помощи отправления сообщений с транспортного уровня и при помощи сообщений с канального уровня. Кроме того, в конкретных реализациях Mobile IPv6 могут предоставляться средства для чтения или изменения внутренних структур данных, описывающих состояние реализации. При сравнении двух различных реализаций эти интерфейсы могут существенно отличаться, так как стандарт не накладывает на них каких-либо ограничений. В некоторых реализациях Mobile IPv6 таких интерфейсов может вообще не быть, поэтому при разработке тестового набора было принято решение не использовать взаимодействие с целевой реализацией при помощи интерфейсов доступа к внутренним управляющим структурам данных.

Более того, с целью построения универсального тестового набора, а также для упрощения синхронизации и анализа результатов, полученных в ходе исполнения сценарных функций, воздействия на целевую реализацию при помощи сообщений с транспортного уровня также не используются. Единственный оставшийся способ взаимодействия заключается в обмене сообщениями через сетевой интерфейс. Таким образом, в принятом подходе воздействиями на тестируемую реализацию, или стимулами являются сообщения со стороны тестирующего узла, а ответами реализации или реакциями - сообщения со стороны мобильного узла.

Для поддержания постоянной достижимости мобильного узла по его домашнему адресу протокол Mobile IPv6 содержит ряд служебных процедур обмена сообщениями между мобильным узлом и домашним агентом или между мобильным узлом и узлом-корреспондентом, например, процедуру регистрации на домашнем агенте (Home Registration), процедуру регистрации на узле-корреспонденте (Correspondent Registration), процедуру обратной маршрутизируемости (Return Routability Procedure) и так далее.

Заметим, что мобильный узел является инициатором выполнения большинства служебных процедур протокола Mobile IPv6. Это создает некоторые дополнительные сложности при организации тестирования.
В соответствии с требованиями стандарта RFC 3775 мобильный узел должен инициировать такие процедуры либо после смены точки подключения, либо по истечении определенного временного интервала после какого-либо события, хотя некоторые служебные обмены сообщениями могут инициироваться мобильным узлом в любое время. Таким образом, единственное явное воздействие, которое может заставить мобильный узел начать служебные обмены сообщениями, - это смена точки подключения мобильного узла. Для упрощения схемы тестового стенда и возможности создания для реализации мобильного узла некоторых внештатных ситуаций было принято решение об имитации процесса смены точки его подключения. При этом фактической смены точки подключения мобильного узла не происходит. Тестовый стенд состоит из двух узлов, соединенных сегментом Ethernet. Один из узлов - тестируемый узел. На тестируемом узле статически настраивается и запускается целевая реализация мобильного узла. Второй узел является инструментальным. На этом узле функционирует тестовый набор, который имитирует для тестируемой реализации некоторую виртуальную сеть. Смена точки подключения мобильного узла имитируется при помощи вспомогательных сообщений Router Advertisement. Такие сообщения периодически отправляются тестовым сценарием от имени маршрутизатора в той сети, в которой мобильный узел находится в данный момент времени. Для имитации смены точки подключения мобильного узла тестовый сценарий прекращает отправление сообщений Router Advertisement от имени маршрутизатора в текущей сети и начинает отправление аналогичных сообщений от имени маршрутизатора в новой сети. Для реализации описанной выше модели тестирующий узел должен имитировать функциональность всех узлов, которые принимают участие в обмене сообщениями с мобильным узлом в модели виртуальной сети, т.е. отправлять все необходимые сообщения от имени узлов виртуальной сети. При этом некоторые из таких сообщений являются частью определенных процедур и должны отправляться синхронно в ответ на сообщения от мобильного узла. Не углубляясь в детали, поведение мобильного узла в целом можно охарактеризовать следующим образом.


При смене точки подключения мобильный узел должен выполнить несколько служебных обменов сообщениями с домашним агентом и узлами-корреспондентами. В результате этих обменов будут установлены необходимые привязки, и мобильный узел станет доступным по своему домашнему адресу. После этого мобильный узел начинает служебные обмены сообщениями только перед истечением времени жизни привязки, домашнего адреса или временного адреса. Заметим, что после перехода в новую сеть мобильный узел может выполнять некоторые из процедур обмена сообщениями параллельно, что делает его поведение недетерминированным. Например, процедура регистрации на узле-корреспонденте может выполняться параллельно с процедурой Mobile Prefix Discovery. Кроме того, стандарт допускает недетерминированное поведение мобильного узла в рамках одной служебной процедуры. Например, перед регистрацией на узле-корреспонденте мобильный узел может выполнить процедуру обратной маршрутизируемости либо полностью, либо частично, а в некоторых случаях может ее не выполнять вообще. Некоторые сообщения тестируемая реализация должна отправлять через определенное время после поступления стимула. Из-за таких особенностей поведения мобильного узла возникают затруднения с определением группы сообщений, которые можно охарактеризовать как воздействие и отклик на него. Такая группа может охватывать несколько служебных процедур, и для нее будет сложно построить спецификации методом Design-by-Contract []. Для того чтобы избежать таких сложностей, используется механизм отложенных реакций инструмента CTesK, который позволяет не указывать в явном виде связь между стимулом и реакцией. Заметим также, что инструмент CTesK, который использовался для разработки тестового набора, позволяет проводить тестирование лишь с использованием стационарных модельных состояний. Однако мобильный узел не имеет стационарных состояний за исключением некоторых внештатных ситуаций. Для преодоления этого ограничения исследовалась возможность применения двух различных подходов. Первый подход заключался в использовании при работе обходчика состояний, близких к стационарным.


Если для привязок и адресов использовать достаточно большие значения времени жизни, то состояние мобильного узла, после смены точки подключения и завершения служебных процедур, можно рассматривать как «приближенно» стационарное, которое пригодно для используемого метода тестирования. Слово «приближенно» используется потому, что такие состояния в действительности не являются стационарными. Для того чтобы мобильный узел находился в таком состоянии длительное время, он должен периодически получать от маршрутизатора сообщения Router Advertisement и выполнять процедуру Neighbor Unreachability Detection. Для обхода графа таких состояний можно ввести группу стимулов, которые производят смену точки подключения мобильного узла. Такие стимулы будут отличаться от отдельных сообщений, отправляемых тестовым сценарием, так как будут действовать на всю виртуальную сеть, а не на мобильный узел в отдельности. При воздействии таким стимулом состояние тестируемой реализации явно не изменяется, а изменяется лишь состояние виртуальной сети в целом. Но благодаря обмену сообщениями между узлами виртуальной сети впоследствии изменится и состояние тестируемой реализации. После воздействия одним из таких стимулов мобильный узел должен через некоторое время перейти в приближенно стационарное состояние, а значит, такие стимулы уже можно использовать в инструменте CTesK. Такой подход использовался в ранней версии тестового набора, который проверял только установление привязок с домашним агентом. Однако при расширении этого тестового набора возникли дополнительные трудности, и от использования таких приближенно стационарных состояний пришлось отказаться. Первая проблема заключается в том, что стандарт RFC 3775 не содержит исчерпывающего описания ограничений на то, какие сообщения мобильный узел может отправлять, находясь в определенном состоянии. Более того, стандарт указывает, что некоторые служебные процедуры, такие как формирование временного адреса и регистрация на узле-корреспонденте, мобильный узел может начать в любой момент времени. Вторая проблема возникает, когда при тестировании мобильного узла необходимо использовать небольшие значения времени жизни для привязок.


Из- за недетерминированного поведения мобильного узла сложно предсказать время, когда привязка будет установлена, а значит и время, когда реализация мобильного узла должна отправить сообщение Binding Update для обновления активно используемой привязки, время жизни которой вскоре истечет. При использовании небольших значений времени жизни привязки такая реакция может возникнуть во время анализа результатов выполнения сценарной функции, что в свою очередь может привести к ошибке в работе обходчика инструмента CTesK. В результате из-за описанных выше проблем от использования стационарных модельных состояний целевой реализации пришлось отказаться. Основные причины использования стационарного тестирования заключаются в следующем: Использование стационарных состояний позволяет проверить, что тестируемая реализация действительно выполнила все необходимые действия, которые были определены спецификацией. Обходчик может работать лишь со стационарными состояниями. Если же исполнение сценарной функции завершается в нестационарном состоянии, то за время, которое необходимо обходчику для начала выполнения следующей сценарной функции, система может перейти в другое состояние. Это может привести к неполному обходу графа модельных состояний или вынесению вердикта о недетерминированном поведении целевой реализации. Второй подход заключается в отказе от стационарного тестирования. При этом необходимо искусственным образом имитировать работу обходчика для случая стационарного тестирования и следить за выполнением всех необходимых действий, которые определены спецификацией. Чтобы проверить, что тестируемая реализация действительно отправила все необходимые сообщения, используется список действий, которые должна произвести система. Действием является отправление целевой реализацией сообщения определенного типа с определенными значениями некоторых полей; значения других его полей могут быть произвольными. Для каждого действия отводится время, за которое система должна его произвести. Действие может быть отменено при получении какого-либо стимула, если оно еще не было выполнено тестируемой реализацией. В стандарте Mobile IPv6 [] требования по уровню обязательности выполнения классифицированы в соответствии с RFC 2119 [].


В предлагаемом подходе для различных групп требований предусмотрены три группы действий: Обязательные действия (obligated) - для требований, обязывающих мобильный узел отправить определенное сообщение (требования, выделенные словами MUST или SHOULD согласно RFC2119). Если тестируемая реализация отправляет такое сообщение в отведенный временной интервал, то сообщается о том, что ее поведение в данном случае удовлетворяет требованию спецификации, которое определяет данное действие. В противном случае выносится вердикт о том, что тестируемая реализация не выполнила данное требование. Для этой группы требований можно задавать альтернативные варианты действий. То есть задаются несколько возможных сообщений для одного требования, и если реализация отправляет одно из таких сообщений, условия требования считаются выполненными. Запрещенные действия (prohibited) - для требований, запрещающих мобильному узлу отправлять определенное сообщение после наступления какого-либо события (требования, выделенные словами MUST NOT или SHOULD NOT). Если данное сообщение было отправлено в выделенный временной интервал, то выносится вердикт о том, что тестируемая реализация нарушила данное требование. В противном случае сообщается о том, что она выполнила требование, определяющее данное действие. Допустимые действия (allowed) - для наблюдения за тем, что мобильный узел реализует некоторую необязательную функциональность протокола (требования, выделенные словом MAY). Если данное сообщение отправлено в отведенный интервал времени, то сообщается о том, что тестируемая реализация поддерживает необязательную функциональность, которая определяется данным требованием. В противном случае ничего не сообщается. Такой подход позволяет явно описывать требования, касающиеся отправления сообщений, и собирать детальную информацию о проверке таких требований, однако предполагает затрату больших усилий при разработке спецификаций, чем в случае со стационарными модельными состояниями. Для того чтобы обеспечить возможность использования стандартного обходчика, в качестве модельных состояний выделяются состояния виртуальной сети в целом, а не группы состояний модели целевой реализации, как это традиционно делается при использовании инструмента CTesK.


С учетом того, что в работе имитируются только виртуальные сети со стационарными маршрутизаторами, домашними агентами и узлами-корреспондентами, состояние виртуальной сети определяется лишь ее топологией, набором ее узлов и точкой подключения мобильного узла. Топология виртуальной сети и набор узлов задаются перед запуском тестового сценария. Таким образом, состояние виртуальной сети определяется лишь точкой подключения мобильного узла. Такие модельные состояния являются стационарными, так как не зависят от поведения реализации и являются объединениями нескольких приближенно стационарных состояний мобильного узла. Для обеспечения такого соответствия необходимо использовать достаточно большой интервал времени, который отводится на исполнение сценарной функции, чтобы тестируемая реализация успела осуществить переход в приближенно стационарное состояние. Кроме того, необходимо описать все действия, определенные стандартом при данном переходе. Конечное приближенно стационарное состояние мобильного узла после перехода в один и тот же сегмент виртуальной сети зависит от поведения других узлов этой сети. В результате введения описанных выше состояний может существенно ухудшиться качество тестирования, поэтому помимо текущей точки подключения мобильного узла в модельных состояниях должен учитываться также и способ, которым мобильный узел был переведен в данную сеть. Сеть, в которой мобильный узел находился до осуществления смены точки подключения, в модельном состоянии не учитывается, так как для любого способа, которым мобильный узел может быть переведен в данную сеть, при обходе графа модельных состояний автоматически будут произведены переходы из всех сетей, из которых это возможно. В предлагаемом подходе не учитывается также и предыдущая история переходов. В подавляющем большинстве случаев предыдущие переходы не оказывают влияния на поведения мобильного узла, а учет таких переходов экспоненциально увеличивает количество модельных состояний. В качестве сценарных функций в тестовом наборе задаются возможные способы перевода мобильного узла из одной сети в другую.


Задача обходчика в таком случае заключается в осуществлении всех возможных переходов для мобильного узла всеми возможными способами. Под различными способами здесь понимается различное поведение узлов виртуальной сети после осуществления смены точки подключения мобильного узла в этой сети, которое определяется отправляемыми ими сообщениями. Для обеспечения полноты тестирования необходимо оказать воздействие всеми возможными стимулами во всех достижимых состояниях, включая начальное состояние. Однако приведение тестируемой реализации мобильного узла в начальное состояние только при помощи обмена сообщениями через сетевой интерфейс не представляется возможным. Это связано с тем, что даже после удаления привязки при возвращении в домашнюю сеть мобильный узел сохраняет некоторую информацию в структурах данных, описывающих его состояние, например, сохраняет адрес домашнего агента. На Рис. 7 изображен пример графа состояний тестового сценария для случая, когда виртуальная сеть состоит только из сегмента домашней сети и одного сегмента внешней сети, и определены только два способа перевода мобильного узла между этими сетями. В состояниях 0, 1 и 2 мобильный узел находится в домашней сети, в состояниях 3 и 4 - во внешней сети. Чтобы отличить способы перевода мобильного узла на рисунке используется разная толщина дуг графа.

Рис. 7.Пример графа состояний тестового сценария Этот пример показывает, что граф состояний тестового сценария не является сильно связным, так как нет дуги, которая возвращала бы тестовый сценарий в начальное состояние. Однако такая дуга необходима для осуществления обходчиком всех возможных переводов мобильного узла из всех достижимых состояний. Это одна из проблем, возникающих при использовании состояний, принятых в нашем подходе. Для гарантированного приведения тестируемой реализации в первоначальное состояние перед выполнением очередного тестового сценария используется перезагрузка целевого узла. Чтобы решить проблему с несвязностью графа состояний, можно было бы ввести стимул, осуществляющий перезагрузку системы, но это приводило бы к большому количеству перезагрузок во время тестирования и заняло бы больше времени на исполнение теста.


Кроме того, сложно было бы отследить, чем именно вызвана перезагрузка: нестабильностью тестируемой реализации или воздействием такого стимула. Вместо введения стимула, осуществляющего перезагрузку целевой реализации, в предлагаемом подходе используются два приема: объединение состояний и обеспечение всех возможных воздействий. А именно, начальное состояние мобильного узла объединяется с состоянием «мобильный узел в домашней сети», в которое он попадает после возвращения в домашнюю сеть, при условии, что тестовый сценарий отправит все необходимые сообщения от имени узлов виртуальной сети. Для обеспечения же перебора всех возможных воздействий в начальном состоянии первоначальные тестовые сценарии разделяются на несколько подсценариев. Этот процесс можно описать следующим образом. Сначала, как и обычно, для проверки определенных групп требований стандарта разрабатываются конкретные тестовые сценарии. Затем после определения всех возможных стимулов, необходимых для обеспечения полноты тестирования, для каждого из этих первоначально разработанных тестовых сценариев создается несколько подсценариев, которые отличаются лишь тем, что на целевую реализацию, находящуюся в первоначальном состоянии, осуществляется воздействие одним конкретным стимулом, отличным от первых стимулов в других подсценариях. При этом общее количество создаваемых подсценариев равно количеству возможных стимулов для данного тестового сценария. Таким образом, на реализацию, находящуюся в первоначальном состоянии, осуществляется воздействие всеми возможными стимулами. На Рис. 8 изображены подсценарии, полученные из предыдущего примера при помощи описанных выше действий. Заметим, что у этого графа дуга из состояния 1 в состояние 3, соответствующая первому способу перевода мобильного узла из домашней сети во внешнюю сеть, обозначена пунктиром. Это означает, что обходчик не обязан осуществлять такое воздействие, так как может считать, что оно уже произведено при выполнении перевода мобильного узла из начального состояния первым способом.

Структура тестового набора и этапы исполнения сценарной функции


Как было указано в предыдущем разделе, для реализации предложенной модели тестирования, тестирующий узел должен имитировать функциональность всех узлов, которые принимают участие в обмене сообщениями с мобильным узлом в виртуальной сети. Имитация функциональности узлов виртуальной сети необходима на протяжении всего выполнения тестового сценария, в том числе и во время обработки результатов вызова сценарных функций. Такая необходимость вызвана тем, что при тестировании используются нестационарные модельные состояния, и большинство служебных сообщений, отправляемых мобильным узлом, является частью синхронных процедур обмена сообщениями с одним из узлов сети. Поэтому часть тестового набора, имитирующая данную функциональность, должна быть реализована вне тестового сценария.

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

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

Все демоны подключаются к одному и тому же сетевому интерфейсу; это упрощает организацию маршрутизации и внештатного функционирования демонов, которое необходимо для проверки некоторых требований спецификации.
Взаимодействие между демонами, там, где это необходимо, должно производится не через сетевой интерфейс, а с использованием других средств, так как все такие сообщения будет получать мобильный узел, если его сетевой интерфейс находится в режиме promiscuous. В предлагаемом тестовом наборе такое взаимодействие необходимо только между демонами узлов-корреспондентов и демонами домашних агентов. Для этого используется общий Binding Update List, в который домашние агенты записывают информацию об установленных привязках. Узлы-корреспонденты используют эту информацию для извлечения из туннеля входящих пакетов и туннелирования исходящих пакетов при обмене сообщениями с мобильным узлом в режиме двустороннего туннелирования. Общая картина выполнения тестового сценария выглядит следующим образом (см. Рис. 9). Перед инициализацией тестового сценария на тестируемом узле должна быть настроена и запущена целевая реализация. Перед началом тестирования запускается процесс под названием кэтчер, который получает и запоминает все сообщения, поступающие на сетевой интерфейс. Затем запускаются необходимые демоны с первоначальными значениями структур данных, которые определяют их поведение. После этого тестовый сценарий выжидает некоторый интервал времени, в течение которого при помощи обмена сообщениями с демонами тестируемая реализация выполняет автоматическую конфигурацию. Рис. 9. Схема исполнения тестового сценария Выполнение тестового сценария заключается в последовательном вызове сценарных функций. При вызове каждой сценарной функции соответствующим образом изменяются внутренние структуры данных, определяющие поведение демонов. Такое изменение состояния и поведения демонов оказывает воздействие на целевую реализацию мобильного узла и заставляет ее выйти из стационарного состояния. Затем тестовый сценарий некоторое время находится в состоянии ожидания, по истечении которого работа сценарной функции завершается, и тестовый сценарий получает от кэтчера пакеты, собранные за время ожидания и обработки результатов вызова предыдущей сценарной функции.Далее производится анализ полученных пакетов и регистрация соответствующих стимулов и реакций. Таким образом, стимулы, которые должны применяться в данной сценарной функции, задаются неявным образом через поведение демонов. После завершения сценария прекращается работа демонов и кэтчера.

В последнее время мобильные устройства


В последнее время мобильные устройства получают все большее распространение, и потребность постоянного доступа к сети Интернет таких устройств является естественной. Предполагается, что в недалеком будущем Интернет примет на вооружение протокол нового поколения IPv6 []. Для поддержки функций мобильности техническим комитетом по проектированию Интернет (Internet Engineering Task Force, IETF) разработано расширение этого нового протокола, получившее название Mobile IPv6, и выпущен документ RFC 3775 "Mobility Support in IPv6" [], который можно рассматривать в качестве будущего стандарта (процесс стандартизации этого расширения, как и самого протокола IPv6, на сегодняшний день еще не завершен). Функциональность Mobile IPv6 нацелена на поддержку целого ряда устройств, в частности, персональных компьютеров, ноутбуков, карманных компьютеров, мобильных телефонов, маршрутизаторов и точек доступа для беспроводных сетей. Очевидно, в перспективе ожидается появление большого количества реализаций Mobile IPv6 от различных производителей. Тестирование соответствия стандартам является одним из основных средств обеспечения совместимости реализаций различных производителей и позволяет решать вопросы повышения надежности и отказоустойчивости глобальной сети. В настоящее время отсутствие средств такого тестирования является одной из причин, препятствующих внедрению перспективных технологий в практику. В Институте системного программирования РАН (ИСП РАН) в течение ряда лет ведутся работы по исследованию и развитию методов формального моделирования телекоммуникационных протоколов. В частности, одним из направлений работ по проекту «Верификация функций безопасности и мобильности протоколов IP», который выполнялся при поддержке гранта РФФИ № 04-07-90308, была разработка тестового набора, обеспечивающего проверку соответствия реализаций стандарту Mobile IPv6. В качестве основы для построения такого тестового набора использовался опыт создания и внедрения разработанной в ИСП РАН методологии тестирования на основе формальных спецификаций UniTESK []. В статье рассматриваются некоторые особенности протокола Mobile IPv6, затрудняющие тестирование реализаций с помощью этой технологии, а также способы преодоления возникших трудностей в рамках ее ограничений.
В качестве объекта тестирования принята реализация основного объекта протокола Mobile IPv6 - мобильного узла (узла, который может совершать перемещения между различными сегментами сети Интернет). Такой выбор обусловлен тем, что тестирование мобильного узла представляет наибольшую сложность, в частности, из-за того, что он является инициатором большинства служебных процедур обмена протокольными сообщениями. Статья содержит восемь разделов, включая введение и заключение. В следующих двух разделах кратко рассматриваются вопросы функционирования протокола Mobile IPv6, а также возможности инструмента CTesK [], реализующего технологию UniTESK. Четвертый раздел посвящен проблемам тестирования мобильного узла и способам их решения. В пятом разделе описываются структура разработанного тестового набора и этапы исполнения сценарных функций. В шестом разделе рассматриваются способы адаптации инструмента CTesK к предложенной схеме тестового набора. Седьмой раздел посвящен результатам применения разработанного тестового набора для тестирования одной из известных реализаций Mobile IPv6. В заключении приведены основные выводы и результаты работы.

В статье описаны особенности тестового


В статье описаны особенности тестового набора, разработанного для проверки соответствия реализаций мобильного узла спецификации протокола Mobile IPv6 []. Тестовый набор разрабатывался при помощи инструмента CTesK, который реализует технологию автоматического тестирования UniTESK. В ходе выполнения работы были выявлены некоторые особенности мобильного узла, которые затрудняют его тестирование с помощью технологии UniTESK, а именно: Мобильный узел является инициатором большинства служебных обменов сообщениями. Некоторые из таких обменов сообщениями можно вызвать неявным образом, создав определенные условия при помощи вспомогательных сообщений. Другие обмены сообщениями мобильный узел может начинать в произвольные моменты времени. В обоих случаях на сообщения со стороны мобильного узла может потребоваться быстрый ответ со стороны тестирующего узла. Спецификация протокола Mobile IPv6 не содержит исчерпывающего описания поведения мобильного узла, поэтому нельзя осуществить перебор всех возможных воздействий во всех состояниях. Спецификация протокола Mobile IPv6 допускает недетерминированное поведение мобильного узла. Однако все эти особенности удалось успешно преодолеть, не выходя за рамки ограничений технологии UniTESK. При разработке тестового набора было обнаружено несколько сложных моментов, связанных с применением инструмента CTesK, а именно: отсутствие у мобильного узла стационарных состояний; сложность использования инвариантов типов данных из-за того, что их проверка производится только автоматически и не может контролироваться; недостаточная информативность при задании формальных спецификаций в виде пред- и постусловий. Для преодоления этих трудностей потребовалось несколько отступить от прямого использования традиционного подхода к разработке тестового набора, задаваемого инструментом CTesK. Тем не менее, благодаря гибкости инструмента, удалось решить поставленную задачу его средствами. Единственное, от чего действительно пришлось отказаться, - это использование стандартных для CTesK средств генерации отчетов о тестировании. Широта и сложность предметной области требует для анализа результатов тестирования существенно большего объема информации, чем предоставляет инструмент. Поэтому был реализован сбор дополнительной информации о ходе тестирования средствами самого тестового набора и разработана система генерации отчета, предназначенная для конкретной задачи. В остальном, несмотря на все выявленные особенности, удалось без существенных трудностей использовать инструмент CTesK для тестирования реализаций мобильного узла.

Аннотация.


В статье рассказывается о технической стороне разработки стандарта Linux Standard Base и связанной с ним инфраструктуре. Описывается использование базы данных для хранения части информации, входящей в стандарт. Обсуждается процесс генерации на основе этих данных как непосредственно текста стандарта, так и сопутствующих объектов - наборов элементарных тестов, заголовочных файлов, отвечающих стандарту LSB, и пр. Также рассматриваются задачи по развитию существующей инфраструктуры, которые планируется решить в рамках совместного проекта ИСП РАН и организации Free Standards Group, под эгидой которой проводится разработка стандарта LSB.



Атомарные требования и тестовые наборы


В настоящее время достаточно сложно получить информацию о существующих тестовых наборах для проверки соответствия стандарту LSB и о покрытии, которое они обеспечивают. Такую информацию изначально планировалось хранить в базе данных стандарта - для этого в таблице Interface есть поле Itested, показывающее, тестируется ли интерфейс тестовыми наборами, используемыми при сертификационном тестировании. Кроме того, есть таблица TestSuite, содержащая информацию о доступных тестовых наборах, а также таблицы TestInt и TestCmd, показывающие, какие интерфейсы и команды покрываются тестовыми наборами.

Однако сейчас нет никакого способа заполнять эти таблицы автоматически - для их заполнения необходимо проводить анализ отчетов о тестировании либо непосредственно тестовых наборов и определять, на тестирование каких интерфейсов и команд нацелен каждый тест. Последний раз такая работа проводилась в середине 2002 года. С тех пор информация, касающаяся тестов и покрытия, в базе данных не обновлялась, и на текущий момент практически полностью устарела. Так, из 32721 интерфейса, включенных в LSB версии 3.1 (учитывая все архитектуры), только 184 помечены как протестированные (Itested='Yes') и еще для 1700 содержатся записи в таблице TestInt (что означает, что для 1700 интерфейсов хотя бы один из тестовых наборов содержит какой-то тест). С командами ситуация несколько лучше - из 141 команды, включенной в стандарт, для 90 существуют тесты.

Кроме того, наличие всего одного поля Itested и записей в таблице TestInt для каждого интерфейса представляется недостаточным. Ведь в случае, если интерфейс является функцией, для него может существовать целый набор требований, и тестовые наборы могут проверять только часть из них. При существующей структуре определить полноту тестирования каждого конкретного интерфейса невозможно.

Для обеспечения более полной информации о покрытии тестами интерфейсов планируется для каждого интерфейса хранить список атомарных требований, и осуществлять привязку тестов не к самим интерфейсам, а к этим атомарным требованиям.
Рассматривается возможность хранить атомарные требования не непосредственно в базе данных, а в отдельных xml-файлах; база данных при этом будет содержать только ссылки на соответствующие xml-файлы. Такая организация представляется более предпочтительной, чем размещение всех требований в БД. Последнее увеличит размер БД в несколько раз, в то время для как большинства инструментов, работающих с БД (генераторы текста стандарта, генераторы библиотек-"заглушек" и т.п.) эти данные не нужны. Атомарные требования необходимо выделять из спецификации интерфейса. В LSB такие спецификации либо создаются вручную и хранятся в отдельных файлах формата sgml, либо вместо детального описания содержится ссылка на другой стандарт, где такое описание присутствует. Таким образом, для выделения атомарных требований необходимо анализировать описания интерфейсов, написанные человеком. Естественно, непосредственно анализ описаний автоматизировать трудно, однако планируется предоставить инструмент, который позволит упростить процесс занесения атомарных требований в базу данных. Задачу существенно усложняет наличие множества ссылок на другие документы - для выделения атомарных требований для всех интерфейсов необходимо иметь тексты всех этих стандартов (на данный момент в описаниях интерфейсов содержатся ссылки на 39 различных документов).

База данных стандарта LSB


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

Free Standards Group дает возможность получить такую информацию для всех сущностей, определенных в стандарте LSB.

Библиотеки-"заглушки" и заголовочные файлы


Говорить о LSB-совместимости можно применительно не только к дистрибутивам Linux, но и к отдельным программ. Дистрибутив соответствует стандарту LSB, если он содержит все объекты, описываемые LSB, с характеристиками, указанными в стандарте. Программа же является LSB-совместимой, если она в своей работе использует только те объекты, которые описаны в LSB. Таким образом, любая LSB-совместимая программа будет работать в любом дистрибутиве, отвечающим требованиям этого стандарта (поскольку LSB стандартизует интерфейсы на бинарном уровне, а не на уровне исходного кода, то для запуска программы на разных дистрибутивах не требуется перекомпиляция).

Однако, даже если программа пишется в дистрибутиве, отвечающим требованиям LSB, нельзя быть уверенным, что она будет LSB-совместимой - ведь соответствие дистрибутива стандарту не означает, что в нем нет каких-то дополнительных интерфейсов или команд, которые могут оказаться задействованы в разрабатываемой программе.

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

Скрипты создают исходный код для библиотек, описанных в LSB, включая туда все определенные в стандарте LSB интерфейсы с соответствующими сигнатурами. Однако генерируемый исходный код всех интерфейсов-функций не содержит ничего полезного - если функция не возвращает никаких значений, то тело функции просто пусто, в противном случае генерируется конструкция, возвращающая какое-нибудь значение требуемого типа. Таким образом, весь этот исходный код может быть скомпилирован, в результате чего и будут получены библиотеки-"заглушки" - эти библиотеки формально содержат все интерфейсы из стандарта LSB и не содержат никаких других интерфейсов, однако функции, содержащиеся в них, ничего не делают.

Помимо библиотек-"заглушек" скрипты создают заголовочные файлы, содержащие описания тех и только тех объектов (типов, констант, функций), которые входят в LSB. При этом свойства этих объектов (размеры типов, значения констант, сигнатуры функций) полностью соответствуют стандарту.

Таким образом, если программу удается скомпилировать в таком окружении (т.е. с использованием только библиотек-"заглушек" и сгенерированных заголовочных файлов), то можно гарантировать, что она использует только объекты, описанные в LSB.

Однако проводить функциональное тестирование программы все-таки необходимо с использованием реальных библиотек. Поэтому для получения уверенности в том, что программа будет выполнять поставленные перед ней задачи на любой LSB-совместимой платформе, функциональное тестирование программы необходимо проводить на дистрибутиве, соответствующем стандарту LSB.

Созданию LSB-совместимых приложений с использованием LSB-совместимого окружения посвящена отдельная книга [], выпущенная разработчиками стандарта и доступная в электронном виде на сайте Free Standards Group.

Чистка базы данных стандарта LSB


В процессе развития стандарта схема базы данных стандарта изменялась не один раз. К сожалению, не все изменения схемы сопровождались соответствующими корректными преобразованиями данных и инструментов, работающих с базой данных. В результате во многих таблицах появились поля, устаревшие с точки зрения структуры базы данных, но по-прежнему используемые частью скриптов. При этом были примеры несогласованности значений устаревших полей со значениями структур, пришедших им на смену. В результате скрипты, использовавшие устаревшие поля, генерировали некорректные данные.

Проиллюстрируем сказанное на примере связи между интерфейсами и архитектурами.

Первые версии стандарта LSB описывали бинарные интерфейсы только для одной архитектуры IA32, и схема базы данных не позволяла хранить информацию о различных архитектурах. Однако уже в LSB версии 1.2 появилась поддержка второй архитектуры (PPC32), и соответствующие изменения претерпела схема БД.

Изначально в таблице Interface, хранящей данные об интерфейсах, было введено специальное поле Iarch, ссылающееся на запись в таблице Architecture. Однако связь между интерфейсами и архитектурами в действительности является связью "многие ко многим": один интерфейс может быть определен для нескольких архитектур. Для таких интерфейсов предлагалось вводить несколько записей в таблице Interface, по одному для каждой архитектуры (соответственно, эти записи различались значением поля Iarch и, возможно, значениями некоторых архитектурно-зависимых свойств).

Практика быстро показала, что решение заводить несколько записей для каждого интерфейса было не очень удачным. При таком подходе во всех таблицах, ссылающихся на интерфейс, приходилось также заводить несколько записей, соответствующих различным записям в таблице интерфейсов. Поскольку большая часть информации об интерфейсе не зависит от архитектуры, во многих таблицах данные просто дублировались, что приводило к неоправданному росту объема данных.

В результате для реализации связей "многие ко многим" между таблицей интерфейсов и таблицей архитектур была создана отдельная таблица ArchInt.
После этого все связи между интерфейсами и архитектурами вносились в таблицу ArchInt, однако поле Iarch убрано не было - к этому моменту многие инструменты, работающие с базой данных, использовали это поле, а для их быстрой переработки не хватало ресурсов. Кроме того, в таблице Interface уже было более 5000 записей, созданных исключительно для реализации связи "многие ко многим" между интерфейсами и архитектурами. Они не были удалены, а в таблицу ArchInt не была занесена соответствующая им информация. Такой "частичный" переход к использованию таблицы ArchInt привел к тому, что часть информации о связи "многие ко многим" хранилась в этой таблице, а часть задавалась дублированием записей с изменением поля Iarch. Часть инструментов была переписана с учетом появления новой таблицы; при этом они учитывали как данные из ArchInt, так и поле Iarch (в основном это относится к скриптам, генерирующим текст стандарта - их корректность имеет наивысший приоритет). Вновь написанные инструменты опирались только на таблицу ArchInt, в то время как часть старых инструментов так и не была переписана и использовала только Iarch. Избавление от проблемы со связями между архитектурами и интерфейсами было произведено в ходе чистки схемы и данных базы данных стандарта LSB на первом этапе разработки новой тестовой инфраструктуры LSB, в четвертом квартале 2006 года. В частности, было удалено поле Iarch, все необходимые данные перенесены в таблицу ArchInt и произведены соответствующие изменения скриптов. Помимо этого, были произведены следующие действия по устранению нестыковок и неоднородностей: Унификация названий полей и типов перечислений, имеющих одинаковую семантику в различных таблицах. Например, статус команд в стандарте хранился в поле Command.Cstatus, имевшем тип enum ('Included', 'Excluded', 'Builtin', 'Unknown'), а статус констант в стандарте хранился в поле Constant.Cstd, имевшем тип enum ('Yes', 'No', 'SrcOnly'). Теперь все поля, обозначающие статус какого-либо объекта в стандарте, имеют имена, оканчивающиеся на "stdstatus", и для всех таких полей используется одно и то же перечисление. Удаление устаревших либо не используемых полей и таблиц. Исправление в таблице Type некорректных значений некоторых полей, полученных при автоматическом заполнении базы.Например, для некоторых типов-перечислений объявление типа не было корректно обработано, и тип не был определен в таблице как перечисление, а ключевое слово "enum" просто присоединялось к имени типа. Согласование типов полей-ссылок с типами полей, на которые они ссылаются. Удаление дублирующихся индексов и добавление индексов, ускоряющих часто используемые запросы к базе данных (на основе анализа скриптов, работающих с БД). Появление дублирующихся индексов было вызвано особенностями архитектуры СУБД MySQL, которая при создании индекса вида (a,b,c) автоматически создает индексы (a,b) и (a).

Генерация текста стандарта


База данных активно используется при генерации текста стандарта LSB. Ведь основное содержание всех документов LSB - это перечень интерфейсов, которые должны присутствовать в системе, и их описаний. Интерфейсы разбиваются по библиотекам либо по классам; кроме того, внутри каждой библиотеки возможна дополнительная группировка, как было указано в предыдущем разделе. Также указывается, какие заголовочные файлы необходимо подключить для использования того или иного интерфейса, а для интерфейсов-функций приводится их сигнатура.

Здесь снова стоит отметить, что стандарт LSB предназначен для обеспечения переносимости приложений на бинарном уровне, а не на уровне исходного кода. Для бинарной переносимости не важно, в каких заголовочных файлах определяются конкретные объекты - главное, чтобы эти объекты находились в заданных стандартом библиотеках. Поэтому в LSB описывается расположение объектов по заголовочным файлам, принятое в большинстве дистрибутивов Linux. Цель этого описания - помочь разработчикам определить местоположение нужного интерфейса в ходе написания программы; однако действительное место описания объекта в конкретном дистрибутиве может отличаться от приведенного в LSB, при этом требования стандарта не будут нарушены, если объект входит в предписанную библиотеку.

Перечни интерфейсов с краткой информацией создаются специальными скриптами на основе сведений из базы данных стандарта LSB. Скрипты создают текст стандарта в формате sgml, используя в некоторых случаях заранее заготовленные шаблоны. На основе сгенерированных sgml-файлов создаются файлы в наиболее распространенных форматах - html, rtf, ps, pdf, а также файлы в текстовом формате (естественно, лишенного такого преимущества остальных форматов, как навигация по ссылкам внутри документа, что полезно при чтении стандарта).

На основе соответствующих таблиц также создаются списки констант и определяемых пользователем типов (перечислений, структур и т.п.), сгруппированных по заголовочным файлам, в которых они описаны, список секций исполняемых файлов формата ELF и список тэгов файлов формата RPM.

Что касается более детальных описаний интерфейсов (например, описания того, что делает функция), то здесь стандарт LSB в большинстве случаев ссылается на другие стандарты (такие, как POSIX, стандарт ISO/IEC 9899 для языка C и т.д.). Информация о том, где искать описание каждого конкретного объекта, также содержится в базе данных стандарта - для этого заведена отдельная таблица, содержащая все стандарты, на которые есть ссылки из LSB, и каждая запись в таблицах объектов ссылается на запись в таблице стандартов. Соответственно в тексте стандарта рядом с каждым интерфейсом указано, где искать его подробное описание.

Описания некоторых интерфейсов содержится непосредственно в LSB, но их число очень невелико (на ноябрь 2006 г. - 454 из 32721 интерфейса, включенных в текст стандарта). Эти описания создаются вручную (также в формате sgml) и автоматически включаются в нужные места при генерации стандарта.

Генерация зависящих от стандарта объектов


Free Standards Group предоставляет средства для генерации не только самого текста стандарта, но и различных объектов, зависящих от этого стандарта. К таким объектам относятся: библиотеки-"заглушки" ("stub libraries"); заголовочные файлы с описаниями объектов, определенных в стандарте LSB; элементарные тесты для проверки соответствия дистрибутива либо приложения стандарту LSB.

Рассмотрим эти объекты подробнее.

Информация о дистрибутивах


Особенностью стандарта LSB является ориентированность на основные дистрибутивы Linux - в стандарт включаются только те объекты, которые присутствуют в последних версиях большинства основных дистрибутивов. (Формально списка "основных дистрибутивов" нет - согласно официальной доктрине, в LSB вносится все то, что "является устоявшейся практикой в мире Linux"; однако в реальной жизни невозможно исследовать все дистрибутивы, и основное внимание уделяется RedHat, SuSe, Mandriva, Asianux, Debian и Ubuntu).

Одним из важных аспектов разработки стандарта является отслеживание списка интерфейсов, команд и пр., используемых в различных версиях дистрибутивов. Если какой-то интерфейс либо команда присутствуют почти везде и востребованы разработчиками приложений, но еще не включены в LSB, то они объявляются кандидатами на включение в следующую версию стандарта. Ручная обработка списка интерфейсов и определение кандидатов на включение в стандарт - трудоемкая работа, и в настоящее время назрела потребность в ее автоматизации.

Для упрощения работы с дистрибутивами планируется, прежде всего, добавить в базу данных таблицу, содержащую список дистрибутивов (включая различные версии одного и того же дистрибутива). Также планируется добавить таблицу с компонентами, содержащимися в этих дистрибутивах (glibc, zlib, Qt, Gtk и т.д.), и привязку записей из этих таблиц к объектам, описываемых стандартом - библиотекам, заголовочным файлам, интерфейсам и пр.

Информацию о составе дистрибутивов (ассортимент и версии входящих в них компонентов, какие интерфейсы/библиотеки/заголовочные файлы содержатся в компонентах и т.п.) планируется заполнять автоматически на основе анализа установленного дистрибутива. В перспективе для занесения сведений об очередной версии дистрибутива в базу данных разработчику необходимо будет лишь запустить утилиты сбора информации о дистрибутиве (естественно, для обеспечения полноты сведений утилиты необходимо запускать на дистрибутиве, установленном в полной комплектации).

При наличии информации об основных дистрибутивах и их составе можно будет автоматически определять объекты, являющиеся кандидатами на включение в стандарт, а также объекты, которые в ближайших версиях стандарта следует объявить устаревшими, а впоследствии удалить.

Информация об архитектурах


Стандарт LSB специфицирует интерфейсы операционной системы на бинарном уровне. Естественно, это делает стандарт зависимым от архитектуры аппаратного обеспечения - для каждой архитектуры необходима своя версия стандарта. Поэтому стандарт LSB содержит различные документы для различных аппаратных платформ - например, все, что относится к стандартной библиотеке C++, описывается в документах LSB-CXX-IA32 (для архитектуры IA32), LSB-CXX-AMD64 (для архитектуры AMD64) и т.д (в LSB версии 3.1 поддерживаются семь архитектур - AMD64, IA32, IA64, PPC32, PPC64, S390 и S390X). Кроме того, есть так называемая общая спецификация LSB (LSB Generic Specification), описывающая объекты, которые должны присутствовать во всех LSB-совместимых реализациях, независимо от аппаратной платформы.

Для хранения списка аппаратных платформ в схеме базы данных предусмотрена таблица Architecture. Многие объекты, информация о которых содержится в базе данных, включены в спецификации для одних платформ и отсутствуют в спецификациях для других. Кроме того, каждый объект, описываемый стандартом, на каждой платформе может иметь какие-то специфические особенности. Поэтому между таблицами объектов и таблицей архитектур существуют связи "многие ко многим", которые реализуются посредством отдельных таблиц, содержащих пары "идентификатор объекта, идентификатор архитектуры". Эти таблицы также содержат те свойства объектов, которые могут иметь различные значения на различных архитектурах (например, значения констант).

Среди идентификаторов архитектур есть одно выделенное значение - "All". Если объект приписан к архитектуре с этим идентификатором, то он должен присутствовать во всех архитектурах, поддерживаемых LSB, и при этом на всех архитектурах его свойства должны быть одинаковы (допускается одно исключение для версий интерфейсов - для интерфейса, приписанного к архитектуре All, можно завести отдельную запись-привязку к конкретной архитектуре, указав там значение версии, не меньшее, чем для архитектуры All).

Безусловно, можно было бы обойтись и заведением необходимого количества записей для объекта (по одной записи для каждой поддерживаемой архитектуры), но идентификатор "All" имеет дополнительную смысловую нагрузку - именно объекты, привязанные к архитектуре All, попадают в общую спецификацию LSB. При отсутствии такого идентификатора для каждого объекта приходилось бы проверять, что он привязан ко всем поддерживаемым архитектурам и при этом обладает на каждой из них одними и теми же свойствами. Такие проверки существенно усложнили бы создание генераторов текста стандарта и связанных с ним объектов, о которых пойдет речь в следующих двух разделах.

Информация об объектах, описанных в LSB


Для стандарта LSB в качестве хранилища объектов, описываемых стандартом, основной информации о них и связей между ними используется так называемая база данных стандарта LSB (LSB Specification Database). Более точно, в этой базе данных содержится информация о следующих объектах: библиотеки (таблица Library); классы (таблица ClassInfo); интерфейсы - LSB является бинарным стандартом и описывает интерфейсы, предоставляемые каждой библиотекой. Все интерфейсы хранятся в таблице Interface и могут иметь следующие типы: Function (функции); Data (данные); Common ("общие интерфейсы", к которым относятся stdin, stdout и им подобные); Alias (интерфейсы, являющиеся синонимами других интерфейсов); заголовочные файлы (таблица Header); константы (таблица Constant); типы данных (таблица Type); команды (таблица Command; под командами здесь понимаются как встроенные команды shell, так и различные утилиты); секции исполняемых файлов формата ELF (таблицы ElfSections и SectionTypes); теги rpm-файлов (таблица RpmTag).

Рис.1.ER-диаграмма сущностей, описываемых стандартом LSB.

Также в базе данных хранятся связи между указанными объектами - каждая константа привязана к заголовочному файлу, в котором она объявляется, интерфейс - к библиотеке, в которой он содержится, либо к классу, если это метод класса, и т.д. ER-диаграмма существующей базы данных приведена на Рис. 1. Все сущности группируются в так называемые модули согласно своему назначению (например, модуль LSB_Сpp содержит все, относящееся к стандартной библиотеке C++, LSB_Toolkit_Qt3 - все, относящееся к библиотеке Qt3, и т.д.). Информация о форматах файлов ELF и RPM относится к модулю LSB_Core, однако база данных этого факта никак не отражает - об этом "знают" только скрипты, генерирующие текст стандарта.

Связи типа "многие ко многим" реализуются посредством использования отдельных таблиц. Самой сложной структурой обладает взаимосвязь таблиц ClassInfo и Interface. Для ее реализации используется несколько вспомогательных таблиц, содержащих информацию о виртуальных таблицах класса (таблица Vtable; каждый класс может иметь одну либо две виртуальные таблицы) и о наследовании (таблица BaseTypes реализует обычное наследование, при описании множественного наследования используется также таблица VMIBaseTypes).

Для удобства интерфейсы и классы, входящие в одну библиотеку, разбиваются на группы согласно их назначению.
Информация о таких группах, на которые разбиваются библиотеки, содержится в таблице LibGroup. Так, например, библиотека librt (функции реального времени) разделена на три группы: Shared Memory Objects (функции для работы с разделяемой памятью); Clock (функции для работы с часами); Timers (функции для работы с таймерами). Аналогично группируются константы и типы данных, описанные в одном заголовочном файле. Информация о таких группах содержится в таблице HeaderGroup. Так, например, файл rpc/rpc_msg.h, который содержит декларации типов и функций для работы с сообщениями, передаваемыми при удаленном вызове процедур (RPC, Remote Procedure Call), делится на следующие группы: accepted_reply (типы, которые описывают ответ на rpc-запрос, принятый сервером); rejected_reply (типы, которые описывают ответ на rpc-запрос, отвергнутый сервером); reply_body (типы, описывающие тело ответа на rpc-запрос); call_body (типы, описывающие тело rpc-запроса); rpc_msg (типы, описывающие весь rpc-запрос); base types (основные типы); default HeaderGroup (сюда относится все, не вошедшее в перечисленные выше группы). Заметим, что типы одной группы могут быть составными типами, определяемыми через типы других групп. Например, типы из группы rpc_msg - это структуры, содержащие тип из call_body либо reply_body и некоторые дополнительные атрибуты.

Элементарные тесты


Одной из главных задач стандартизации является проведение сертификационного тестирования на соответствие реализации стандарту. LSB, как и большинство промышленных стандартов, имеет большой объем, и написать тесты для проведения сертификации вручную не представляется возможным. Необходима автоматизация процесса создания сертификационного тестового набора.

Наличие базы данных стандарта позволяет сгенерировать на ее основе набор элементарных тестов, определяющих, присутствуют ли в системе все объекты, описанные в стандарте LSB, и соответствуют ли их характеристики (значения констант, сигнатуры функций и т.п.) тем, которые указаны в стандарте. В частности, генерируются следующие наборы тестов: cmdchk - проверка того, что в системе присутствуют все описанные в LSB команды, и соответствующие исполняемые файлы находятся в директориях, определенных стандартом (хотя для многих команд имена директорий не указаны); devchk - проверка наличия в системе всех заголовочных файлов, описанных в LSB, и наличия в этих файлах описаний всех требуемых стандартом констант и типов (функции данный тест не проверяет). Для констант проверяется, верно ли определены их значений, для типов, определяемых в заголовочных файлах, вычисляется размер и сравнивается с тем, который должен быть согласно LSB; libchk - проверка наличия в системе всех библиотек, описанных в LSB, а также проверка содержимого этих библиотек на соответствие стандарту (тестируется наличие в библиотеке всех необходимых интерфейсов с сигнатурами, определенными в стандарте).

Перечисленные выше тесты нацелены на проверку соответствия дистрибутивов Linux стандарту LSB. Кроме этого, существуют скрипты для генерации тестовых наборов, нацеленных на проверку соответствия стандарту отдельного приложения. К таким тестовым наборам относятся: appchk - статический анализ файла на предмет использования им библиотек и интерфейсов, не входящих в LSB; dynchk - проверка корректности использования приложением интерфейсов, определенных в LSB (разработка этих тестов еще не завершена); elfchk - проверка корректности заданного elf-файла (используется в тестах appchk); rpmchk - проверка корректности заданного rpm-файла (используется в тестах appchk).

Подробнее о перечисленных выше тестовых наборах и использовании базы данных стандарта при их генерации можно узнать в [].

Несмотря на то, что перечисленные выше тесты не осуществляют никаких сложных проверок, возможность их автоматической генерации существенно упрощает процесс проверки соответствия дистрибутивов и приложений требованиям LSB.
Например, если бы разработчикам тестов было доступно только текстовое описание заголовочных файлов со всем содержимым (константами, типами и функциями), то даже для элементарной проверки, выполняемой тестовым набором devchk, им пришлось бы вручную извлекать из текста всю необходимую информацию. А этот процесс может занять довольно продолжительное время (стандарт LSB описывает более 6000 различных констант и более 8000 типов для 411 заголовочных файлов). Кроме того, при таких объемах информации неизбежны ошибки, связанные с человеческим фактором. Более сложные тесты на основе базы данных стандарта создать нельзя, поскольку она содержит далеко не всю информацию, присутствующую в тексте LSB. В частности, нельзя создать тестовый набор для проверки соответствия стандарту поведения функций, а именно такие тесты наиболее важны для сертификационного тестирования. Однако описание поведения функций на данный момент имеется только в виде текста, написанного человеком, и для автоматического создания тестов необходимо проводить формализацию этого текста (пример подхода к формализации приведен в [], там же имеется краткий обзор других существующих подходов). О планах по добавлению в базу данных стандарта LSB более детальной информации об интерфейсах и о других направлениях развития инфраструктуры LSB можно узнать в следующем разделе.

Литература


1.обратноLinux Standard Base wiki.
2.обратноFree Standards Group wiki.
3.обратноLinux Standard Base Team. Building Applications with the Linux Standard Base. 2005.
4.обратноStuart Anderson, Matt Elder. Run-time Testing of LSB Applications. Proceedings of the Linux Symposium, July 2004.
5.обратноА. И. Гриневич, В. В. Кулямин, Д. А. Марковцев, А. К. Петренко, В. В. Рубанов, А. В. Хорошилов. Использование формальных методов для обеспечения соблюдения программных стандартов. Труды Института Системного Программирования. Т.10, с. 51-68, 2006.



Планы по развитию инфраструктуры LSB


В настоящее время в ИСП РАН в рамках совместного проекта с Free Standards Group проводится разработка тестовой инфраструктуры, предназначенной для усовершенствования процесса сертификации на соответствие стандарту LSB. Помимо собственно процесса тестирования, проект затрагивает и многие смежные области, в том числе базу данных стандарта и работающие с ней инструменты.

Поддержка версий LSB


В настоящее время база данных содержит информацию только для текущей версии стандарта. Чтобы посмотреть, что входило в какую-либо из предыдущих версий, необходимо взять из CVS-репозитория FSG соответствующую версию базы данных. Также можно сгенерировать и текст стандарта определенной версии, однако для этого необходимо, помимо нужной версии базы данных, взять соответствующие версии скриптов, генерирующих текст стандарта - ведь со временем изменения вносятся как в схему базы данных, так и в сами скрипты.

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

В рамках совместного проекта ИСП РАН и FSG планируется добавить в базу данных поддержку хранения информации для различных версий стандарта LSB, а также доработать все скрипты, чтобы они могли генерировать файлы, соответствующие определенной версии стандарта.

Планируется воссоздать историю изменений стандарта LSB, начиная с версии 3.0. Что касается более ранних версий, то вопрос о предоставлении исторической информации для них остается открытым - в первые годы своего существования стандарт и построенная вокруг него инфраструктура переживали революционные изменения (переход к поддержке нескольких архитектур, разбиение на модули), и хранить историю в полном объеме было вряд ли целесообразно, а ее воссоздание может потребовать значительных усилий.

в современном мире программного обеспечения,


Стандарты играют существенную роль в современном мире программного обеспечения, внося единообразие в сложные программные комплексы. Наличие стандартов в области операционных систем позволяет разработчикам создавать приложения, взаимодействующие с операционной системой, не изучая при этом детали реализации объекта взаимодействия. Для написания программы, соответствующей какому-либо стандарту, разработчику необходимо изучить текст этого стандарта. Большинство стандартов попадают к пользователям в виде электронных документов либо напечатанных книг, и объем их достаточно велик. Однако во многих случаях процесс разработки упростится, если некоторые сведения из стандарта будут доступны в какой-то другой форме, более формальной, чем текст, и не требующей изучения человеком. Например, для гарантии того, что в программе будут использоваться только описанные стандартом функции, специфицированные в заданных заголовочных файлах, полезно иметь такие файлы, содержащие описания только стандартных функций. Использование только этих заголовочных файлов при создании программы гарантировало бы отсутствие обращений к функциям, не входящим в стандарт. Но ручное создание таких заголовочных файлов на основе текста стандарта - трудоемкое занятие (например, стандарт LSB [] содержит описание 18955 функций из 465 заголовочных файлов), и во многих случаях (особенно при разработке небольших приложений) разработчики предпочитают полагаться на свое знание текста стандарта. Вполне возможно, что у создателей стандарта имеется необходимая информация в виде, удобном для разработчика, однако процесс создания большинства стандартов скрыт от постороннего взора. Тексты многих стандартов доступны только за плату, а доступа к данным, которые (возможно) используются при создании текста стандарта, нет. Нетрудно видеть, что такое положение вещей противоречит идеологии open source, согласно которой пользователь должен иметь возможность получить не только готовый продукт, но и все необходимое для его самостоятельной сборки и внесения в него изменений. Конечно, требование открытости относится, прежде всего, к исходным кодам программ, однако многие сторонники open source переносят эту идеологию и на смежные области. И одним из примеров здесь является стандарт LSB, описывающий базовые интерфейсы операционной системы на бинарном уровне. Во Free Standards Group [], под эгидой которой проводится разработка LSB, используется специфический подход, открывающий всем желающим всю "кухню" по производству стандарта. Каждый может бесплатно получить все необходимое не только для генерации текста стандарта, но и для автоматического создания сопутствующих наборов программ и исходного кода. О том, как устроена инфраструктура, связанная со стандартом LSB, и какие существуют планы по ее развитию, и рассказывается в данной статье.

Free Standards Group смогла успешно


Free Standards Group смогла успешно перенести идеологию open source на процесс разработки стандарта LSB, создав инфраструктуру, предоставляющую каждому желающему возможность самостоятельно генерировать текст стандарта и многие связанные с ним объекты. Наличие базы данных стандарта позволяет предоставлять пользователям более удобные способы изучения сущностей, описанных в LSB, чем простое чтение текста. Существующий подход уже доказал свою состоятельность - с его применением создавались все версии стандарта, начиная с 1.0. Естественно, за это время как схема базы данных стандарта LSB, так и использующие эту базу данных скрипты претерпели существенные изменения, однако основные идеи, заложенные в основу используемого подхода, остаются неизменными. Тем не менее, в своем текущем состоянии инфраструктура LSB удовлетворяет не все потребности, возникающие у пользователей, и есть много предложений по ее дальнейшему развитию. Прежде всего, необходимо предоставлять пользователю информацию о дистрибутивах и о наличии в них тех или иных сущностей, описанных в LSB. Также важно предоставить более простые способы получения данных о предыдущих версиях стандарта. Для создания сертификационных наборов, обеспечивающих хорошее покрытие, представляется важным иметь в базе данных более детальную информацию об интерфейсах. Все эти задачи планируется реализовать в рамках совместного проекта ИСП РАН и Free Standards Group по развитию инфраструктуры LSB.