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