15db71995Sopenharmony_ci# Loader Testing Framework
25db71995Sopenharmony_ci
35db71995Sopenharmony_ciThe loader testing framework is a mocking environment which fakes many of the global systems that vulkan requires to run. This allows the writing of tests against a known driver, layer, and system configuration.
45db71995Sopenharmony_ci
55db71995Sopenharmony_ciThe framework consists of:
65db71995Sopenharmony_ci* Test ICD
75db71995Sopenharmony_ci* Test Layer
85db71995Sopenharmony_ci* Shim
95db71995Sopenharmony_ci* Manifest Writer
105db71995Sopenharmony_ci* Utility
115db71995Sopenharmony_ci* Test Environment
125db71995Sopenharmony_ci* Tests
135db71995Sopenharmony_ci
145db71995Sopenharmony_ci
155db71995Sopenharmony_ci## Running
165db71995Sopenharmony_ci
175db71995Sopenharmony_ciBy default the Vulkan-Loader repo doesn't enable testing.
185db71995Sopenharmony_ci
195db71995Sopenharmony_ciTo turn on building of the tests, set `BUILD_TESTS=ON` in the CMake configuration.
205db71995Sopenharmony_ci
215db71995Sopenharmony_ciUse the CMake configuration `UPDATE_DEPS=ON` to automatically get all required test dependencies.
225db71995Sopenharmony_ciOr Ensure that `googletest` is in the `external` directory.
235db71995Sopenharmony_ciAnd on Windows only, ensure that the `Detours` library is in the `external` directory.
245db71995Sopenharmony_ci
255db71995Sopenharmony_ciLinux & macOS only: The CMake Configuration `LOADER_ENABLE_ADDRESS_SANITIZER` can be used to
265db71995Sopenharmony_cienable Address Sanitizer.
275db71995Sopenharmony_ci
285db71995Sopenharmony_ciRun the test executables as normal
295db71995Sopenharmony_ci
305db71995Sopenharmony_ciThe executables available are:
315db71995Sopenharmony_ci* `test_regression`
325db71995Sopenharmony_ci
335db71995Sopenharmony_ciAlternatively, in the build directory run `ctest` to start the test framework.
345db71995Sopenharmony_ci
355db71995Sopenharmony_ciUse the `ctest` command line parameter `--output-on-failure` to printout logs in failing tests
365db71995Sopenharmony_ci
375db71995Sopenharmony_ciNote: The test framework was not designed to allow multiple tests to be run in parallel due to the extensive use of files and folders on the system.
385db71995Sopenharmony_ci
395db71995Sopenharmony_ci
405db71995Sopenharmony_ci## Components
415db71995Sopenharmony_ci
425db71995Sopenharmony_ci### Test ICD and Layer
435db71995Sopenharmony_ciThe Test ICD and Test Layer have much of their configuration available at runtime to allow maximal test setup flexibility.
445db71995Sopenharmony_ciHowever exported functions in the icd or layer library binaries are an integral part of the configuration but are baked into the binary, thus not runtime configurable.
455db71995Sopenharmony_ciTo account for that there are multiple binaries of the Test ICD and Test Layer, each being a distinct combination of exported functions.
465db71995Sopenharmony_ciThe `test_icd.cpp` and `test_layer.cpp` files use macro defines to allow the build system to specify which functions should be exported.
475db71995Sopenharmony_ci```c
485db71995Sopenharmony_ci#if defined(TEST_ICD_EXPORT_NEW_FUNCTION)
495db71995Sopenharmony_ciFRAMEWORK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNewFunction() { ... }
505db71995Sopenharmony_ci#endif
515db71995Sopenharmony_ci```
525db71995Sopenharmony_ciThe `CMakeLists.txt` is responsible for creating the various binaries for the Test ICD and Test Layer with the corresponding macros defined to alter which functions are exported.
535db71995Sopenharmony_ciSince the test framework needs to know where the binaries are located in the build tree, the `framework_config.h` file contains the absolute paths to all of the libraries that CMake has defined.
545db71995Sopenharmony_ciThis allows C++ tests to include the header and know exactly what `.dll`/`.so` file to use.
555db71995Sopenharmony_ciSince the paths aren't known until build time, CMake processes the `framework_config.h.in` file which contains the names of the libraries that CMake recognizes and replaces the names with the path on the system to the library.
565db71995Sopenharmony_ci
575db71995Sopenharmony_ciTo add a new configuration for a ICD or layer, the changes needed are as follows:
585db71995Sopenharmony_ci* Add the relevant functions & macro guards in `test_icd.cpp` or `test_layer.cpp`
595db71995Sopenharmony_ci* In the `framework/icd/CMakeLists.txt` or `framework/layer/CMakeLists.txt`, add a new SHARED library using the icd/layer source files.
605db71995Sopenharmony_ci  * We are going to use `new_function` as the name of this new configuration for clarity in this documentation.
615db71995Sopenharmony_ci```cmake
625db71995Sopenharmony_ciadd_library(test_icd_export_new_function SHARED ${TEST_ICD_SOURCES})
635db71995Sopenharmony_ci```
645db71995Sopenharmony_ci* Use `target_compile_definitions()` cmake command on the new library to add the specified exports.
655db71995Sopenharmony_ci```cmake
665db71995Sopenharmony_citarget_compile_definitions(test_icd_export_new_function PRIVATE TEST_ICD_EXPORT_NEW_FUNCTION=1)
675db71995Sopenharmony_ci```
685db71995Sopenharmony_ci* Create a new `.def` file with the same name as the library and place it in the `icd\export_definitions` or `layer\export_definitions` folder.
695db71995Sopenharmony_ci  * This file is needed in 32 bit windows to prevent name mangling in `.dll`.
705db71995Sopenharmony_ci* Add all of the exported functions in this file.
715db71995Sopenharmony_ci  * Include all exported functions, not just the newly added functions.
725db71995Sopenharmony_ci```
735db71995Sopenharmony_ciLIBRARY test_icd_export_new_function
745db71995Sopenharmony_ciEXPORTS
755db71995Sopenharmony_ci    <exported_function_0>
765db71995Sopenharmony_ci    <exported_function_1>
775db71995Sopenharmony_ci    ...
785db71995Sopenharmony_ci```
795db71995Sopenharmony_ci* Go back to the `CMakeLists.txt` and add this def file to the library by using `target_sources`, that way the compiler knows which .def file to use for each library
805db71995Sopenharmony_ci```cmake
815db71995Sopenharmony_ciif (WIN32)
825db71995Sopenharmony_ci    target_sources(test_icd_export_new_function PRIVATE export_definitions/test_icd_new_function.def)
835db71995Sopenharmony_ciendif()
845db71995Sopenharmony_ci```
855db71995Sopenharmony_ci* To make the library accessible to tests, add the name of the library to `framework/framework_config.h.in`
865db71995Sopenharmony_ci```c
875db71995Sopenharmony_ci#define TEST_ICD_PATH_NEW_FUNCTION "$<TARGET_FILE:test_icd_export_new_function>"
885db71995Sopenharmony_ci```
895db71995Sopenharmony_ci
905db71995Sopenharmony_ci### Shim
915db71995Sopenharmony_ciBecause the loader makes many calls to various OS functionality, the framework intercepts certain calls and makes a few of its own calls to OS functionality to allow proper isolation of the loader from the system it is running on.
925db71995Sopenharmony_ciThe shim is a SHARED library on windows and apple and is a STATIC library on linux. This is due to the nature of the dynamic linker and how overriding functions operates on different operating systems.
935db71995Sopenharmony_ci#### Linux
945db71995Sopenharmony_ci
955db71995Sopenharmony_ciOn linux the dynamic linker will use functions defined in the program binary in loaded `.so`'s if the name matches, allowing easy interception of system calls.
965db71995Sopenharmony_ci##### Overridden functions
975db71995Sopenharmony_ci* opendir
985db71995Sopenharmony_ci* access
995db71995Sopenharmony_ci* fopen
1005db71995Sopenharmony_ci
1015db71995Sopenharmony_ci#### MacOS
1025db71995Sopenharmony_ciRedirects the following functions: opendir, access fopen.
1035db71995Sopenharmony_ciThe dynamic linker on MacOS requires a bit of tweaking to make it use functions defined in the program binary to override system functions in `.so`'s.
1045db71995Sopenharmony_ci##### Overridden functions
1055db71995Sopenharmony_ci* opendir
1065db71995Sopenharmony_ci* access
1075db71995Sopenharmony_ci* fopen
1085db71995Sopenharmony_ci
1095db71995Sopenharmony_ci#### Windows
1105db71995Sopenharmony_ciWindows requires a significantly larger number of functions to be intercepted to isolate it sufficiently enough for testing.
1115db71995Sopenharmony_ciTo facilitate that an external library `Detours` is used.
1125db71995Sopenharmony_ciIt is an open source Microsoft library and supports all of the necessary functionality needed for loader testing.
1135db71995Sopenharmony_ciNote that the loader calls more system functions than are directly overridden with Detours.
1145db71995Sopenharmony_ciThis is due to some functions being used to query other functions, which the shim library intercepts and returns its own versions of system functions instead, such as `CreateDXGIFactory1`.
1155db71995Sopenharmony_ci
1165db71995Sopenharmony_ci##### Overridden functions
1175db71995Sopenharmony_ci* GetSidSubAuthority
1185db71995Sopenharmony_ci* EnumAdapters2
1195db71995Sopenharmony_ci* QueryAdapterInfo
1205db71995Sopenharmony_ci* CM_Get_Device_ID_List_SizeW
1215db71995Sopenharmony_ci* CM_Get_Device_ID_ListW
1225db71995Sopenharmony_ci* CM_Locate_DevNodeW
1235db71995Sopenharmony_ci* CM_Get_DevNode_Status
1245db71995Sopenharmony_ci* CM_Get_Device_IDW
1255db71995Sopenharmony_ci* CM_Get_Child
1265db71995Sopenharmony_ci* CM_Get_DevNode_Registry_PropertyW
1275db71995Sopenharmony_ci* CM_Get_Sibling
1285db71995Sopenharmony_ci* GetDesc1
1295db71995Sopenharmony_ci* CreateDXGIFactory1
1305db71995Sopenharmony_ci
1315db71995Sopenharmony_ci### Utility
1325db71995Sopenharmony_ci
1335db71995Sopenharmony_ciThere are many utilities that the test framework and tests have access to. These include:
1345db71995Sopenharmony_ci* Including common C and C++ headers
1355db71995Sopenharmony_ci* `FRAMEWORK_EXPORT` - macro used for exporting shared library funtions
1365db71995Sopenharmony_ci* Environment Variable Wrapper: `EnvVarWrapper` for creating, setting, getting, and removing environment variables in a RAII manner
1375db71995Sopenharmony_ci* Windows API error handling helpers
1385db71995Sopenharmony_ci* filesystem abstractions:
1395db71995Sopenharmony_ci  * `fs::path` - wrapper around std::string that has a similar API to C++17's `filesystem::path` library
1405db71995Sopenharmony_ci  * `create_folder`/`delete_folder`
1415db71995Sopenharmony_ci  * `FolderManager`
1425db71995Sopenharmony_ci    * Creates a new folder with the given name at construction time.
1435db71995Sopenharmony_ci    * Allows writing manifests and files (eg, icd or layer binaries)
1445db71995Sopenharmony_ci    * Automatically destroys the folder and all contained files at destruction
1455db71995Sopenharmony_ci* LibraryWrapper - load and unload `.dll`/`.so`'s automatically
1465db71995Sopenharmony_ci* DispatchableHandle - helper class for managing the creation and freeing of dispatchable handles
1475db71995Sopenharmony_ci* VulkanFunctions - Loads the vulkan-loader and queries all used functions from it
1485db71995Sopenharmony_ci  * If a test needs to use vulkan functions, they must be loaded here
1495db71995Sopenharmony_ci* Vulkan Create Info Helpers - provide a nice interface for setting up a vulkan creat info struct.
1505db71995Sopenharmony_ci  * InstanceCreateInfo
1515db71995Sopenharmony_ci  * DeviceCreateInfo
1525db71995Sopenharmony_ci  * DeviceQueueCreateInfo
1535db71995Sopenharmony_ci* Comparison operators for various vulkan structs
1545db71995Sopenharmony_ci
1555db71995Sopenharmony_ci### Test Environment
1565db71995Sopenharmony_ci
1575db71995Sopenharmony_ciThe `test_environment.h/.cpp` contains classes which organize all the disparate parts of the framework into an easy to use entity that allows setting up and configuring the environment tests run in.
1585db71995Sopenharmony_ci
1595db71995Sopenharmony_ciThe core components are:
1605db71995Sopenharmony_ci* InstWrapper - helper to construct and then destroy a vulkan instance during tests
1615db71995Sopenharmony_ci* DeviceWrapper - helper to construct and then destroy a vulkan device during tests
1625db71995Sopenharmony_ci* PlatformShimWrapper - opens and configures the platform specific shim library
1635db71995Sopenharmony_ci  * Sets up the overrides
1645db71995Sopenharmony_ci  * Resets state (clearing out previous test state)
1655db71995Sopenharmony_ci  * Sets the `VK_LOADER_DEBUG` env var to `all`.
1665db71995Sopenharmony_ci* TestICD|LayerHandle - corresponds to a single ICD or Layer on the system
1675db71995Sopenharmony_ci  * Loads the Test ICD/Layer library
1685db71995Sopenharmony_ci  * Allows easily 'resetting' the Test ICD/Layer
1695db71995Sopenharmony_ci* TestICD|LayerDetails - holder of data used for constructing ICD and Layers
1705db71995Sopenharmony_ci  * Contains the name and api version of the icd or layer binary
1715db71995Sopenharmony_ci  * LayerDetails also contains the manifest,
1725db71995Sopenharmony_ci* FrameworkEnvironment
1735db71995Sopenharmony_ci  * Owns the platform shim
1745db71995Sopenharmony_ci  * Creates folders for the various manifest search locations, including
1755db71995Sopenharmony_ci    * icd manifest
1765db71995Sopenharmony_ci    * explicit layer manifests
1775db71995Sopenharmony_ci    * implicit layer manifests
1785db71995Sopenharmony_ci    * null - necessary empty folder to make the loader find nothing when we want it to
1795db71995Sopenharmony_ci  * Sets these folders up as the redirection locations with the platform shim
1805db71995Sopenharmony_ci  * Allows adding ICD's and Layers
1815db71995Sopenharmony_ci    * Writes the json manifest file to the correct folder
1825db71995Sopenharmony_ci
1835db71995Sopenharmony_ciThe `FrameworkEnvironment` class is used to easily create 'environments'.
1845db71995Sopenharmony_ci
1855db71995Sopenharmony_ciThe `add_XXX()` member functions of `FrameworkEnvironment` make it easy to add drivers and layers to the environment a test runs in.
1865db71995Sopenharmony_ci
1875db71995Sopenharmony_ciThe `get_test_icd()` and `get_test_layer()` functions allow querying references to the underlying
1885db71995Sopenharmony_cidrivers and layers that are in the environment, allowing quick modification of their behavior.
1895db71995Sopenharmony_ci
1905db71995Sopenharmony_ciThe `reset_test_icd()` and `reset_test_layer()` are similar to the above functions but additionally
1915db71995Sopenharmony_cireset the layer or driver to its initial state.
1925db71995Sopenharmony_ciUse this if you need to reset a driver during a test.
1935db71995Sopenharmony_ciThese functions are called on the drivers and layers when the framework is being create in each test.
194