diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4ddfb11 --- /dev/null +++ b/.clang-format @@ -0,0 +1,62 @@ +--- +BasedOnStyle: Chromium +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +#AllowAllArgumentsOnNextLine: 'false' +#AlignConsecutiveAssignments: None +#AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: true +AllowAllParametersOfDeclarationOnNextLine: true +#AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +#AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +ColumnLimit: 140 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +IndentCaseLabels: true +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBlockIndentWidth: 4 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +#SortIncludes: Never +SpaceAfterCStyleCast: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpacesBeforeTrailingComments: 2 +Standard: Auto +TabWidth: 4 +UseTab: Never +#NamespaceMacros: +# - DECLARE_TEMPLATED_OPENDAQ_INTERFACE_T +# - DECLARE_TEMPLATED_OPENDAQ_INTERFACE_T_U +# - DECLARE_OPENDAQ_INTERFACE_EX +# - DECLARE_OPENDAQ_INTERFACE +FixNamespaceComments: false +#MacroBlockBegin: "^BEGIN_NAMESPACE_OPENDAQ$" +#MacroBlockEnd: "^END_NAMESPACE_OPENDAQ" +#IndentPPDirectives: BeforeHash +#SeparateDefinitionBlocks: Always +... diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..72081c9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[{*.{cpp,h},CMakeLists.txt,*.rtclass,*.cmake,*.json}] +indent_style = space +indent_size = 4 +tab_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.yml] +ident_style = space +ident_size = 2 +tab_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8884b5b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto +*.[tT][xX][tT] text +*.[sS][hH] text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ae29e7d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,100 @@ +name: Build and Test + +on: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +jobs: + build-and-test: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + generator: Ninja + - os: windows-latest + generator: "Visual Studio 17 2022" + + runs-on: ${{ matrix.os }} + + steps: + - name: Install additional dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get install -y --no-install-recommends mono-runtime libmono-system-json-microsoft4.0-cil libmono-system-data4.0-cil + + - name: Checkout project repo + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.event.client_payload.branch || github.ref }} + + - name: Configure project with CMake + run: cmake -B build/output -S . -G "${{ matrix.generator }}" -DLT_STREAMING_MODULES_ENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug + + - name: Build project with CMake + run: cmake --build build/output --config Debug + + - name: Run project tests with CMake + run: ctest --test-dir build/output --output-on-failure -C Debug + + install-build-and-test: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + generator: Ninja + - os: windows-latest + generator: "Visual Studio 17 2022" + + runs-on: ${{ matrix.os }} + env: + INSTALL_PREFIX: ${{ github.workspace }}/opendaq_install + + steps: + - name: Install additional dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get install -y --no-install-recommends mono-runtime libmono-system-json-microsoft4.0-cil libmono-system-data4.0-cil + + - name: Checkout module + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.event.client_payload.branch || github.ref }} + path: module + + - name: Read openDAQ version + working-directory: module + run: | + opendaq_ref=$(cat external/opendaq_ref) + echo "OPENDAQ_REF=$opendaq_ref" >> $GITHUB_ENV + + - name: Checkout openDAQ + uses: actions/checkout@v4 + with: + repository: openDAQ/openDAQ + ref: ${{ env.OPENDAQ_REF }} + path: opendaq + + - name: Configure, build and install openDAQ + working-directory: opendaq + run: | + cmake -B build/output -S . -G "${{ matrix.generator }}" -DOPENDAQ_ENABLE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="${{ env.INSTALL_PREFIX }}" + cmake --build build/output --config Release + cmake --install build/output --config Release + + - name: Add DLL path (Windows only) + if: matrix.os == 'windows-latest' + run: echo "${{ env.INSTALL_PREFIX }}/lib" >> $env:GITHUB_PATH + + - name: Configure project with CMake + working-directory: module + run: cmake -B build/output -S . -G "${{ matrix.generator }}" -DLT_STREAMING_MODULES_ENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release -DopenDAQ_DIR="${{ env.INSTALL_PREFIX }}/lib/cmake/opendaq/" + + - name: Build project with CMake + working-directory: module + run: cmake --build build/output --config Release + + - name: Run project tests with CMake + working-directory: module + run: ctest --test-dir build/output --output-on-failure -C Release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..295355a --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# file types +*.bin +*.bak +*.cache +*.check_cache +*.db +*.dcu +*.depend +*.exp +*.filters +*.idb +*.ilk +*.list +*.log +*.obj +*.orig +*.pdb +*.pyc +*.rule +*.rsm +*.stamp +*.stat +*.suo +*.tlog +*.user + +# IDE files +.idea/ +.idea_/ +.vs/ +.vscode/ +__history/ +__recovery/ +__pycache__/ + +# build and backup folders +/_build* +/build* +/build_win +/cmake-build* +/out* +bckp + +# cmake +CMakeUserPresets.json +CMakeSettings.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6e35776 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +set(CMAKE_POLICY_VERSION_MINIMUM 3.5) +cmake_minimum_required(VERSION 3.25) + +# set project variables +set(REPO_NAME LtStreamingModulesLegacy) +set(REPO_OPTION_PREFIX DAQMODULES_LT_STREAMING) + +add_subdirectory(cmake) + +opendaq_setup_module_project(${REPO_OPTION_PREFIX} ${REPO_NAME}) +opendaq_setup_module_subfolders(${REPO_OPTION_PREFIX} ${REPO_NAME}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..99c8a24 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,222 @@ +{ + "version": 4, + "configurePresets": [ + { + "name": "debug", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "binaryDir": "build/${presetName}" + }, + { + "name": "release", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + }, + "binaryDir": "build/${presetName}" + }, + { + "name": "gcc", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "gcc", + "CMAKE_CXX_COMPILER": "g++" + } + }, + { + "name": "clang", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "intel-llvm", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "icx", + "CMAKE_CXX_COMPILER": "icpx" + } + }, + { + "name": "ninja", + "hidden": true, + "generator": "Ninja" + }, + { + "name": "msvc-17", + "hidden": true, + "generator": "Visual Studio 15 2017", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "hostOS": [ "Windows" ] + } + } + }, + { + "name": "msvc-22", + "hidden": true, + "generator": "Visual Studio 17 2022", + "inherits": [ + "msvc-17" + ] + }, + { + "name": "msvc-x86", + "hidden": true, + "architecture": "Win32", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "hostOS": [ "Windows" ] + } + } + }, + { + "name": "msvc-x64", + "hidden": true, + "architecture": "x64", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "hostOS": [ "Windows" ] + } + } + }, + { + "name": "full", + "hidden": true + }, + { + "name": "ci", + "hidden": false, + "inherits": [ + "full" + ] + }, + { + "name": "full/release", + "hidden": true, + "displayName": "Full - Release", + "inherits": [ + "release", + "full" + ] + }, + { + "name": "full/debug", + "hidden": true, + "displayName": "Full - Release", + "inherits": [ + "debug", + "full" + ] + }, + { + "name": "x86/msvc-17/full", + "displayName": "[MSVC 17] Full - x86", + "inherits": [ + "full/release", + "msvc-17", + "msvc-x86" + ] + }, + { + "name": "x64/msvc-17/full", + "displayName": "[MSVC 17] Full - x64", + "inherits": [ + "full/release", + "msvc-17", + "msvc-x64" + ] + }, + { + "name": "x86/msvc-22/full", + "displayName": "[MSVC 22] Full - x86", + "inherits": [ + "full/release", + "msvc-22", + "msvc-x86" + ] + }, + { + "name": "x64/msvc-22/full", + "displayName": "[MSVC 22] Full - x64", + "inherits": [ + "full/release", + "msvc-22", + "msvc-x64" + ] + }, + { + "name": "x64/gcc/full/debug", + "displayName": "[GCC] Full - Debug", + "inherits": [ + "full/debug", + "gcc", + "ninja" + ] + }, + { + "name": "x64/gcc/full/release", + "displayName": "[GCC] Full - Release", + "inherits": [ + "full/release", + "gcc", + "ninja" + ] + }, + { + "name": "x64/clang/full/debug", + "displayName": "[Clang] Full - Debug", + "inherits": [ + "full/debug", + "clang", + "ninja" + ] + }, + { + "name": "x64/clang/full/release", + "displayName": "[Clang] Full - Release", + "inherits": [ + "full/release", + "clang", + "ninja" + ] + }, + { + "name": "x64/intel-llvm/full/debug", + "displayName": "[IntelLLVM] Full - Debug", + "inherits": [ + "full/debug", + "intel-llvm", + "ninja" + ] + }, + { + "name": "x64/intel-llvm/full/release", + "displayName": "[IntelLLVM] Full - Release", + "inherits": [ + "full/release", + "intel-llvm", + "ninja" + ] + } + ] +} diff --git a/LICENSE b/LICENSE index 261eeb9..1c17a0a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -174,28 +174,3 @@ of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..de859f0 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,14 @@ +set(CMAKE_FOLDER "cmake") + +list(APPEND CMAKE_MESSAGE_CONTEXT cmake) +set(CURR_MESSAGE_CONTEXT ${CMAKE_MESSAGE_CONTEXT}) + +message(STATUS "Import functions and macro from opendaq-cmake-utils repo") +include(FetchContent) +FetchContent_Declare( + opendaq-cmake-utils + GIT_REPOSITORY https://github.com/openDAQ/opendaq-cmake-utils.git + GIT_TAG main + GIT_PROGRESS ON +) +FetchContent_MakeAvailable(opendaq-cmake-utils) diff --git a/cmake/ModuleOptions.cmake b/cmake/ModuleOptions.cmake new file mode 100644 index 0000000..664ffd9 --- /dev/null +++ b/cmake/ModuleOptions.cmake @@ -0,0 +1,12 @@ +if(DEFINED DAQMODULES_LT_STREAMING_CMAKE_OPTIONS_INCLUDED) + return() +endif() +set(DAQMODULES_LT_STREAMING_CMAKE_OPTIONS_INCLUDED TRUE) + +cmake_dependent_option( + DAQMODULES_LT_STREAMING_ENABLE_SIGGEN_INTEGRATION_TESTS + "Enable websocket streaming integration tests" + ON + "OPENDAQ_ENABLE_TESTS AND DAQMODULES_LT_STREAMING_BUILDING_AS_SUBMODULE OR DAQMODULES_LT_STREAMING_ENABLE_TESTS AND NOT DAQMODULES_LT_STREAMING_BUILDING_AS_SUBMODULE" + OFF +) diff --git a/external/Boost.cmake b/external/Boost.cmake new file mode 100644 index 0000000..2e86169 --- /dev/null +++ b/external/Boost.cmake @@ -0,0 +1,4 @@ +opendaq_add_required_boost_libs( + asio + beast +) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt new file mode 100644 index 0000000..f53d83a --- /dev/null +++ b/external/CMakeLists.txt @@ -0,0 +1,8 @@ +set(CMAKE_FOLDER external) +list(APPEND CMAKE_MESSAGE_CONTEXT external) + +opendaq_setup_module_default_dependencies(${REPO_OPTION_PREFIX}) + +add_subdirectory(spdlog EXCLUDE_FROM_ALL) +add_subdirectory(nlohmann_json) +add_subdirectory(streaming_protocol) diff --git a/external/nlohmann_json/CMakeLists.txt b/external/nlohmann_json/CMakeLists.txt new file mode 100644 index 0000000..bde5330 --- /dev/null +++ b/external/nlohmann_json/CMakeLists.txt @@ -0,0 +1,9 @@ +set(JSON_Install ON) + +opendaq_dependency( + NAME nlohmann_json + REQUIRED_VERSION 3.11.3 + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_REF v3.11.3 + EXPECT_TARGET nlohmann_json::nlohmann_json +) diff --git a/external/opendaq_ref b/external/opendaq_ref new file mode 100644 index 0000000..88d050b --- /dev/null +++ b/external/opendaq_ref @@ -0,0 +1 @@ +main \ No newline at end of file diff --git a/external/spdlog/CMakeLists.txt b/external/spdlog/CMakeLists.txt new file mode 100644 index 0000000..5274432 --- /dev/null +++ b/external/spdlog/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SPDLOG_INSTALL ON CACHE BOOL "" FORCE) +set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "" FORCE) +set(SPDLOG_WCHAR_FILENAMES ON CACHE BOOL "" FORCE) + +opendaq_dependency( + NAME spdlog + REQUIRED_VERSION 1.16.0 + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_REF v1.16.0 + EXPECT_TARGET spdlog::spdlog + PATCH_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/patches/001-periodic_worker_init_func.patch +) diff --git a/external/spdlog/patches/001-periodic_worker_init_func.patch b/external/spdlog/patches/001-periodic_worker_init_func.patch new file mode 100644 index 0000000..d011083 --- /dev/null +++ b/external/spdlog/patches/001-periodic_worker_init_func.patch @@ -0,0 +1,23 @@ +diff --git a/include/spdlog/details/periodic_worker.h b/include/spdlog/details/periodic_worker.h +index d05245cb..3252e53a 100644 +--- a/include/spdlog/details/periodic_worker.h ++++ b/include/spdlog/details/periodic_worker.h +@@ -21,14 +21,16 @@ namespace details { + class SPDLOG_API periodic_worker { + public: + template +- periodic_worker(const std::function &callback_fun, ++ periodic_worker(const std::function &init_thread_fun, ++ const std::function &callback_fun, + std::chrono::duration interval) { + active_ = (interval > std::chrono::duration::zero()); + if (!active_) { + return; + } + +- worker_thread_ = std::thread([this, callback_fun, interval]() { ++ worker_thread_ = std::thread([this, init_thread_fun, callback_fun, interval]() { ++ init_thread_fun(); + for (;;) { + std::unique_lock lock(this->mutex_); + if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) { diff --git a/external/streaming_protocol/CMakeLists.txt b/external/streaming_protocol/CMakeLists.txt index be75a99..104be8b 100644 --- a/external/streaming_protocol/CMakeLists.txt +++ b/external/streaming_protocol/CMakeLists.txt @@ -1,13 +1,13 @@ set(STREAMING_PROTOCOL_ALWAYS_FETCH_DEPS ON CACHE BOOL "" FORCE) -if (OPENDAQ_ENABLE_WS_SIGGEN_INTEGRATION_TESTS) +if (${REPO_OPTION_PREFIX}_ENABLE_SIGGEN_INTEGRATION_TESTS) set(STREAMING_PROTOCOL_TOOLS ON CACHE BOOL "" FORCE) endif() opendaq_dependency( NAME streaming_protocol - REQUIRED_VERSION 1.2.7 + REQUIRED_VERSION 1.2.8 GIT_REPOSITORY https://github.com/openDAQ/streaming-protocol-lt.git - GIT_REF v1.2.7 + GIT_REF v1.2.8-dev EXPECT_TARGET daq::streaming_protocol ) diff --git a/module_version b/module_version new file mode 100644 index 0000000..c06dab4 --- /dev/null +++ b/module_version @@ -0,0 +1 @@ +3.31.0dev \ No newline at end of file diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt new file mode 100644 index 0000000..214be03 --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,12 @@ +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) + +if (MSVC) + add_compile_options(/wd4100) +endif() + +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif() + +add_subdirectory(websocket_streaming_client_module) +add_subdirectory(websocket_streaming_server_module) diff --git a/modules/websocket_streaming_client_module/CMakeLists.txt b/modules/websocket_streaming_client_module/CMakeLists.txt index be07a8f..1d79140 100644 --- a/modules/websocket_streaming_client_module/CMakeLists.txt +++ b/modules/websocket_streaming_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -set_cmake_folder_context(TARGET_FOLDER_NAME) -project(WebsocketStreamingClientModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES C CXX) +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) +project(WebsocketStreamingClientModule VERSION ${${REPO_OPTION_PREFIX}_VERSION} LANGUAGES C CXX) if (MSVC) # loss of data / precision, unsigned <--> signed @@ -16,6 +16,6 @@ endif() add_subdirectory(src) -if (OPENDAQ_ENABLE_TESTS) +if (${REPO_OPTION_PREFIX}_BUILDING_AS_SUBMODULE AND OPENDAQ_ENABLE_TESTS OR ${REPO_OPTION_PREFIX}_ENABLE_TESTS) add_subdirectory(tests) -endif() +endif() \ No newline at end of file diff --git a/modules/websocket_streaming_client_module/src/CMakeLists.txt b/modules/websocket_streaming_client_module/src/CMakeLists.txt index f6f495c..8d08b72 100644 --- a/modules/websocket_streaming_client_module/src/CMakeLists.txt +++ b/modules/websocket_streaming_client_module/src/CMakeLists.txt @@ -15,7 +15,7 @@ set(SRC_Srcs module_dll.cpp websocket_streaming_client_module_impl.cpp ) -prepend_include(${TARGET_FOLDER_NAME} SRC_Include) +opendaq_prepend_include(${TARGET_FOLDER_NAME} SRC_Include) source_group("module" FILES ${MODULE_HEADERS_DIR}/websocket_streaming_client_module_impl.h ${MODULE_HEADERS_DIR}/module_dll.h @@ -27,15 +27,16 @@ source_group("module" FILES ${MODULE_HEADERS_DIR}/websocket_streaming_client_mod add_library(${LIB_NAME} SHARED ${SRC_Include} ${SRC_Srcs} ) -add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) +add_library(${OPENDAQ_SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) if (MSVC) target_compile_options(${LIB_NAME} PRIVATE /bigobj) endif() -target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq - PRIVATE daq::discovery - daq::websocket_streaming +target_link_libraries(${LIB_NAME} PUBLIC ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq + PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::discovery + $ # required for discovery + ${OPENDAQ_SDK_TARGET_NAMESPACE}::websocket_streaming ) target_include_directories(${LIB_NAME} PUBLIC $ @@ -44,4 +45,4 @@ target_include_directories(${LIB_NAME} PUBLIC $()->setModuleInfo(moduleInfo)); + auto device = WebsocketClientDevice(context, parent, localId, strPtr, deviceType); // Set the connection info for the device auto host = String(""); diff --git a/modules/websocket_streaming_client_module/tests/CMakeLists.txt b/modules/websocket_streaming_client_module/tests/CMakeLists.txt index a251317..108b503 100644 --- a/modules/websocket_streaming_client_module/tests/CMakeLists.txt +++ b/modules/websocket_streaming_client_module/tests/CMakeLists.txt @@ -8,15 +8,11 @@ set(TEST_SOURCES test_websocket_streaming_client_module.cpp add_executable(${TEST_APP} ${TEST_SOURCES} ) -target_link_libraries(${TEST_APP} PRIVATE daq::test_utils - ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} +target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils gtest + ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} ) add_test(NAME ${TEST_APP} COMMAND $ WORKING_DIRECTORY $ ) - -if (OPENDAQ_ENABLE_COVERAGE) - setup_target_for_coverage(${TEST_APP}coverage ${TEST_APP} ${TEST_APP}coverage) -endif() diff --git a/modules/websocket_streaming_client_module/tests/test_app.cpp b/modules/websocket_streaming_client_module/tests/test_app.cpp index d92f41f..2d76abc 100644 --- a/modules/websocket_streaming_client_module/tests/test_app.cpp +++ b/modules/websocket_streaming_client_module/tests/test_app.cpp @@ -1,15 +1,10 @@ #include -#include +#include -#include -#include #include int main(int argc, char** args) { - daq::daqInitializeCoreObjectsTesting(); - daqInitModuleManagerLibrary(); - testing::InitGoogleTest(&argc, args); testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); diff --git a/modules/websocket_streaming_client_module/tests/test_websocket_streaming_client_module.cpp b/modules/websocket_streaming_client_module/tests/test_websocket_streaming_client_module.cpp index 36782c2..88916be 100644 --- a/modules/websocket_streaming_client_module/tests/test_websocket_streaming_client_module.cpp +++ b/modules/websocket_streaming_client_module/tests/test_websocket_streaming_client_module.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -97,33 +96,6 @@ TEST_F(WebsocketStreamingClientModuleTest, CreateDeviceConnectionFailed) ASSERT_THROW(module.createDevice("daq.lt://127.0.0.1", nullptr), NotFoundException); } -//TEST_F(WebsocketStreamingClientModuleTest, CreateConnectionString) -//{ -// auto context = NullContext(); -// ModulePtr module; -// createModule(&module, context); -// -// StringPtr connectionString; -// -// ServerCapabilityConfigPtr serverCapabilityIgnored = ServerCapability("test", "test", ProtocolType::Unknown); -// ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapabilityIgnored)); -// ASSERT_FALSE(connectionString.assigned()); -// -// ServerCapabilityConfigPtr serverCapability = ServerCapability("OpenDAQLTStreaming", "OpenDAQLTStreaming", ProtocolType::Streaming); -// ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); -// -// serverCapability.addAddress("123.123.123.123"); -// ASSERT_EQ(module.createConnectionString(serverCapability), "daq.lt://123.123.123.123:7414"); -// -// serverCapability.setPort(1234); -// ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); -// ASSERT_EQ(connectionString, "daq.lt://123.123.123.123:1234"); -// -// serverCapability.addProperty(StringProperty("Path", "/path")); -// ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); -// ASSERT_EQ(connectionString, "daq.lt://123.123.123.123:1234/path"); -//} - TEST_F(WebsocketStreamingClientModuleTest, CreateStreamingWithNullArguments) { auto module = CreateModule(); diff --git a/modules/websocket_streaming_server_module/CMakeLists.txt b/modules/websocket_streaming_server_module/CMakeLists.txt index 0b5b926..12e32a4 100644 --- a/modules/websocket_streaming_server_module/CMakeLists.txt +++ b/modules/websocket_streaming_server_module/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.10) -set_cmake_folder_context(TARGET_FOLDER_NAME) -project(WebsocketStreamingServerModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) +project(WebsocketStreamingServerModule VERSION ${${REPO_OPTION_PREFIX}_VERSION} LANGUAGES CXX) add_subdirectory(src) -if (OPENDAQ_ENABLE_TESTS) +if (${REPO_OPTION_PREFIX}_BUILDING_AS_SUBMODULE AND OPENDAQ_ENABLE_TESTS OR ${REPO_OPTION_PREFIX}_ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/modules/websocket_streaming_server_module/src/CMakeLists.txt b/modules/websocket_streaming_server_module/src/CMakeLists.txt index 2f25750..9ab307a 100644 --- a/modules/websocket_streaming_server_module/src/CMakeLists.txt +++ b/modules/websocket_streaming_server_module/src/CMakeLists.txt @@ -17,7 +17,7 @@ set(SRC_Srcs module_dll.cpp websocket_streaming_server_impl.cpp ) -prepend_include(${TARGET_FOLDER_NAME} SRC_Include) +opendaq_prepend_include(${TARGET_FOLDER_NAME} SRC_Include) source_group("module" FILES ${MODULE_HEADERS_DIR}/websocket_streaming_server_module_impl.h ${MODULE_HEADERS_DIR}/websocket_streaming_server_impl.h @@ -32,17 +32,22 @@ add_library(${LIB_NAME} SHARED ${SRC_Include} ${SRC_Srcs} ) -add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) +add_library(${OPENDAQ_SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) -target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq - PRIVATE daq::websocket_streaming +if (MSVC) + target_compile_options(${LIB_NAME} PRIVATE /bigobj) +endif() + +target_link_libraries(${LIB_NAME} PUBLIC ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq + PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::websocket_streaming ) + target_include_directories(${LIB_NAME} PUBLIC $ $ $ ) opendaq_set_module_properties(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) -create_version_header(${LIB_NAME}) +opendaq_create_version_header(${LIB_NAME}) diff --git a/modules/websocket_streaming_server_module/tests/CMakeLists.txt b/modules/websocket_streaming_server_module/tests/CMakeLists.txt index 02df280..21de9c6 100644 --- a/modules/websocket_streaming_server_module/tests/CMakeLists.txt +++ b/modules/websocket_streaming_server_module/tests/CMakeLists.txt @@ -8,21 +8,11 @@ set(TEST_SOURCES test_websocket_streaming_server_module.cpp add_executable(${TEST_APP} ${TEST_SOURCES} ) -target_link_libraries(${TEST_APP} PRIVATE daq::test_utils - daq::opendaq_mocks - ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} - Taskflow::Taskflow +target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils gtest + ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} ) add_test(NAME ${TEST_APP} COMMAND $ WORKING_DIRECTORY $ ) - -if (MSVC) # Ignoring warning for the Taskflow - target_compile_options(${TEST_APP} PRIVATE /wd4324) -endif() - -if (OPENDAQ_ENABLE_COVERAGE) - setup_target_for_coverage(${TEST_APP}coverage ${TEST_APP} ${TEST_APP}coverage) -endif() diff --git a/modules/websocket_streaming_server_module/tests/test_app.cpp b/modules/websocket_streaming_server_module/tests/test_app.cpp index 64dd0cc..29a34d8 100644 --- a/modules/websocket_streaming_server_module/tests/test_app.cpp +++ b/modules/websocket_streaming_server_module/tests/test_app.cpp @@ -1,16 +1,9 @@ -#include -#include -#include #include -#include +#include #include int main(int argc, char** args) { - daq::daqInitializeCoreObjectsTesting(); - daqInitModuleManagerLibrary(); - daqInitOpenDaqLibrary(); - testing::InitGoogleTest(&argc, args); testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); diff --git a/modules/websocket_streaming_server_module/tests/test_websocket_streaming_server_module.cpp b/modules/websocket_streaming_server_module/tests/test_websocket_streaming_server_module.cpp index 65307c0..971ff8d 100644 --- a/modules/websocket_streaming_server_module/tests/test_websocket_streaming_server_module.cpp +++ b/modules/websocket_streaming_server_module/tests/test_websocket_streaming_server_module.cpp @@ -6,20 +6,9 @@ #include #include #include -#include #include -#include -#include -#include - -class WebsocketStreamingServerModuleTest : public testing::Test -{ -public: - void TearDown() override - { - } -}; +using WebsocketStreamingServerModuleTest = testing::Test; using namespace daq; static ModulePtr CreateModule(ContextPtr context = NullContext()) @@ -29,32 +18,6 @@ static ModulePtr CreateModule(ContextPtr context = NullContext()) return module; } -static InstancePtr CreateTestInstance() -{ - const auto logger = Logger(); - const auto moduleManager = ModuleManager("[[none]]"); - const auto authenticationProvider = AuthenticationProvider(); - const auto context = Context(Scheduler(logger), logger, TypeManager(), moduleManager, authenticationProvider); - - const ModulePtr deviceModule(MockDeviceModule_Create(context)); - moduleManager.addModule(deviceModule); - - const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); - moduleManager.addModule(fbModule); - - const ModulePtr daqWebsocketStreamingServerModule = CreateModule(context); - moduleManager.addModule(daqWebsocketStreamingServerModule); - - auto instance = InstanceCustom(context, "localInstance"); - for (const auto& deviceInfo : instance.getAvailableDevices()) - instance.addDevice(deviceInfo.getConnectionString()); - - for (const auto& [id, _] : instance.getAvailableFunctionBlockTypes()) - instance.addFunctionBlock(id); - - return instance; -} - static PropertyObjectPtr CreateServerConfig(const InstancePtr& instance) { auto config = instance.getAvailableServerTypes().get("OpenDAQLTStreaming").createDefaultConfig(); @@ -132,7 +95,7 @@ TEST_F(WebsocketStreamingServerModuleTest, ServerConfig) TEST_F(WebsocketStreamingServerModuleTest, CreateServer) { - auto device = CreateTestInstance(); + auto device = Instance(); auto module = CreateModule(device.getContext()); auto config = CreateServerConfig(device); @@ -141,7 +104,7 @@ TEST_F(WebsocketStreamingServerModuleTest, CreateServer) TEST_F(WebsocketStreamingServerModuleTest, CreateServerFromInstance) { - auto device = CreateTestInstance(); + auto device = Instance(); auto config = CreateServerConfig(device); ASSERT_NO_THROW(device.addServer("OpenDAQLTStreaming", config)); diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt new file mode 100644 index 0000000..704326b --- /dev/null +++ b/shared/CMakeLists.txt @@ -0,0 +1,17 @@ +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) + +if (MSVC) + add_compile_options(/wd4100) + + # loss of data / precision, unsigned <--> signed + # + # 'argument' : conversion from 'type1' to 'type2', possible loss of data + # https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4244 + add_compile_options(/wd4244) + + # 'var' : conversion from 'size_t' to 'type', possible loss of data + # https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4267 + add_compile_options(/wd4267) +endif() + +add_subdirectory(libraries) diff --git a/shared/libraries/CMakeLists.txt b/shared/libraries/CMakeLists.txt new file mode 100644 index 0000000..1492fab --- /dev/null +++ b/shared/libraries/CMakeLists.txt @@ -0,0 +1,3 @@ +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) + +add_subdirectory(websocket_streaming) diff --git a/shared/libraries/websocket_streaming/CMakeLists.txt b/shared/libraries/websocket_streaming/CMakeLists.txt index a89b800..107a10f 100644 --- a/shared/libraries/websocket_streaming/CMakeLists.txt +++ b/shared/libraries/websocket_streaming/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -set_cmake_folder_context(TARGET_FOLDER_NAME ${SDK_TARGET_NAMESPACE}_websocket_streaming) +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME ${OPENDAQ_SDK_TARGET_NAMESPACE}_websocket_streaming) project(OpenDaqStreaming VERSION 4.0.0 LANGUAGES CXX @@ -7,6 +7,6 @@ project(OpenDaqStreaming add_subdirectory(src) -if (OPENDAQ_ENABLE_TESTS) +if (${REPO_OPTION_PREFIX}_ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_factory.h b/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_factory.h index 183082c..4b7fa34 100644 --- a/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_factory.h +++ b/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_factory.h @@ -23,9 +23,10 @@ BEGIN_NAMESPACE_OPENDAQ_WEBSOCKET_STREAMING inline DevicePtr WebsocketClientDevice(const ContextPtr& context, const ComponentPtr& parent, const StringPtr& localId, - const StringPtr& connectionString) + const StringPtr& connectionString, + const DeviceTypePtr& type) { - DevicePtr obj(createWithImplementation(context, parent, localId, connectionString)); + DevicePtr obj(createWithImplementation(context, parent, localId, connectionString, type)); return obj; } diff --git a/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_impl.h b/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_impl.h index f0fa615..92dcd3b 100644 --- a/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_impl.h +++ b/shared/libraries/websocket_streaming/include/websocket_streaming/websocket_client_device_impl.h @@ -28,7 +28,8 @@ class WebsocketClientDeviceImpl : public Device explicit WebsocketClientDeviceImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, - const StringPtr& connectionString); + const StringPtr& connectionString, + const DeviceTypePtr& type); protected: void removed() override; @@ -49,6 +50,7 @@ class WebsocketClientDeviceImpl : public Device std::unordered_map deviceSignals; std::vector orderedSignalIds; StringPtr connectionString; + DeviceTypePtr deviceType; StreamingPtr websocketStreaming; }; diff --git a/shared/libraries/websocket_streaming/src/CMakeLists.txt b/shared/libraries/websocket_streaming/src/CMakeLists.txt index 495ed9a..4da86a8 100644 --- a/shared/libraries/websocket_streaming/src/CMakeLists.txt +++ b/shared/libraries/websocket_streaming/src/CMakeLists.txt @@ -1,5 +1,5 @@ set(BASE_NAME websocket_streaming) -set(LIB_NAME ${SDK_TARGET_NAME}_${BASE_NAME}) +set(LIB_NAME ${OPENDAQ_SDK_TARGET_NAME}_${BASE_NAME}) set(SRC_Cpp signal_descriptor_converter.cpp streaming_client.cpp @@ -32,7 +32,7 @@ set(SRC_PublicHeaders ) set(INCLUDE_DIR ../include/websocket_streaming) -prepend_include(${INCLUDE_DIR} SRC_PublicHeaders) +opendaq_prepend_include(${INCLUDE_DIR} SRC_PublicHeaders) set(SRC_PrivateHeaders @@ -44,7 +44,7 @@ add_library(${LIB_NAME} STATIC ${SRC_Cpp} ${SRC_PrivateHeaders} ) -add_library(${SDK_TARGET_NAMESPACE}::${BASE_NAME} ALIAS ${LIB_NAME}) +add_library(${OPENDAQ_SDK_TARGET_NAMESPACE}::${BASE_NAME} ALIAS ${LIB_NAME}) if(BUILD_64Bit OR BUILD_ARM) set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) @@ -58,8 +58,8 @@ target_include_directories(${LIB_NAME} PUBLIC $ ) -target_link_libraries(${LIB_NAME} PUBLIC daq::streaming_protocol - daq::opendaq +target_link_libraries(${LIB_NAME} PUBLIC ${OPENDAQ_SDK_TARGET_NAMESPACE}::streaming_protocol + ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq ) # Fix daq::streaming_protocol` not properly propagating linking requirements on Windows diff --git a/shared/libraries/websocket_streaming/src/input_signal.cpp b/shared/libraries/websocket_streaming/src/input_signal.cpp index 09a6352..2450fcd 100644 --- a/shared/libraries/websocket_streaming/src/input_signal.cpp +++ b/shared/libraries/websocket_streaming/src/input_signal.cpp @@ -459,7 +459,6 @@ DataType InputConstantDataSignal::convertToNumeric(const nlohmann::json& jsonNum throw std::out_of_range("Value out of range"); return static_cast(numeric); } - throw std::invalid_argument("Conversion failed - invalid sample type"); } template diff --git a/shared/libraries/websocket_streaming/src/websocket_client_device_impl.cpp b/shared/libraries/websocket_streaming/src/websocket_client_device_impl.cpp index fb09862..287c971 100644 --- a/shared/libraries/websocket_streaming/src/websocket_client_device_impl.cpp +++ b/shared/libraries/websocket_streaming/src/websocket_client_device_impl.cpp @@ -12,9 +12,11 @@ BEGIN_NAMESPACE_OPENDAQ_WEBSOCKET_STREAMING WebsocketClientDeviceImpl::WebsocketClientDeviceImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, - const StringPtr& connectionString) + const StringPtr& connectionString, + const DeviceTypePtr& type) : Device(ctx, parent, localId) , connectionString(connectionString) + , deviceType(type) { if (!this->connectionString.assigned()) DAQ_THROW_EXCEPTION(ArgumentNullException, "connectionString cannot be null"); @@ -31,7 +33,9 @@ void WebsocketClientDeviceImpl::removed() DeviceInfoPtr WebsocketClientDeviceImpl::onGetInfo() { - return DeviceInfo(connectionString, "WebsocketClientPseudoDevice"); + auto info = DeviceInfo(connectionString, "WebsocketClientPseudoDevice"); + info.setDeviceType(deviceType); + return info; } void WebsocketClientDeviceImpl::activateStreaming() diff --git a/shared/libraries/websocket_streaming/tests/CMakeLists.txt b/shared/libraries/websocket_streaming/tests/CMakeLists.txt index 3f63dc5..254d147 100644 --- a/shared/libraries/websocket_streaming/tests/CMakeLists.txt +++ b/shared/libraries/websocket_streaming/tests/CMakeLists.txt @@ -6,7 +6,6 @@ add_executable(${TEST_APP} test_signal_descriptor_converter.cpp test_streaming.cpp test_websocket_client_device.cpp - test_signal_generator.cpp test_app.cpp ) @@ -15,11 +14,12 @@ if (MSVC) endif() target_link_libraries(${TEST_APP} PRIVATE - ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} - daq::opendaq - daq::opendaq_mocks - daq::streaming_protocol - ${SDK_TARGET_NAMESPACE}::test_utils + ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} + ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq + ${OPENDAQ_SDK_TARGET_NAMESPACE}::streaming_protocol + ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils + ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks + gtest ) set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) @@ -29,7 +29,3 @@ add_test(NAME ${TEST_APP} COMMAND $ WORKING_DIRECTORY $ ) - -if(OPENDAQ_ENABLE_COVERAGE) - setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) -endif() diff --git a/shared/libraries/websocket_streaming/tests/streaming_test_helpers.h b/shared/libraries/websocket_streaming/tests/streaming_test_helpers.h index 484e3a4..63a9014 100644 --- a/shared/libraries/websocket_streaming/tests/streaming_test_helpers.h +++ b/shared/libraries/websocket_streaming/tests/streaming_test_helpers.h @@ -54,7 +54,7 @@ namespace streaming_test_helpers moduleManager.addModule(fbModule); auto instance = InstanceCustom(context, "localInstance"); - instance.addDevice("daqmock://client_device"); + instance.addDevice("daq.root://default_client"); instance.addDevice("daqmock://phys_device"); instance.addFunctionBlock("mock_fb_uid"); diff --git a/shared/libraries/websocket_streaming/tests/test_signal_generator.cpp b/shared/libraries/websocket_streaming/tests/test_signal_generator.cpp deleted file mode 100644 index c0f6194..0000000 --- a/shared/libraries/websocket_streaming/tests/test_signal_generator.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -using namespace daq; - -class SignalGeneratorTest : public testing::Test -{ -public: - ContextPtr context; - SignalConfigPtr signal; - SignalGenerator::GenerateSampleFunc stepFunction10; - SignalGenerator::GenerateSampleFunc stepFunction100; - - void SetUp() override - { - context = NullContext(); - signal = createSignal(); - initFunctions(); - } - - void initFunctions() - { - stepFunction10 = [](uint64_t tick, void* sampleOut) - { - int* intOut = (int*) sampleOut; - *intOut = tick % 10; - }; - - stepFunction100 = [](uint64_t tick, void* sampleOut) - { - int* intOut = (int*) sampleOut; - *intOut = tick % 100; - }; - } - - std::vector calculateExpectedSamples(uint64_t startTick, size_t sampleCount, const SignalGenerator::GenerateSampleFunc& function) - { - auto samples = std::vector(sampleCount); - - for (size_t i = 0; i < sampleCount; i++) - function(startTick + i, samples.data() + i); - - return samples; - } - - bool compareSamples(int* expected, void* packetData, size_t sampleCount) - { - return std::memcmp(expected, packetData, sampleCount * sizeof(int)) == 0; - } - -private: - SignalConfigPtr createTimeSignal() - { - const size_t nanosecondsInSecond = 1000000000; - auto delta = nanosecondsInSecond / 1000; - - auto descriptor = DataDescriptorBuilder() - .setSampleType(SampleType::UInt64) - .setRule(LinearDataRule(delta, 0)) - .setTickResolution(Ratio(1, nanosecondsInSecond)) - .setOrigin("1970-01-01T00:00:00") - .setName("Time") - .build(); - - return SignalWithDescriptor(context, descriptor, nullptr, "Time"); - } - - SignalConfigPtr createSignal() - { - auto descriptor = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("Step").build(); - - auto domainSignal = createTimeSignal(); - auto signal = SignalWithDescriptor(context, descriptor, nullptr, "ByteStep"); - signal.setDomainSignal(domainSignal); - return signal; - } -}; - - -TEST_F(SignalGeneratorTest, CreateSignal) -{ - auto reader = PacketReader(signal); - auto packets = reader.readAll(); - ASSERT_EQ(packets.getCount(), 1u); - ASSERT_EQ(packets[0].getType(), PacketType::Event); - - EventPacketPtr eventPacket = packets[0]; - ASSERT_EQ(eventPacket.getEventId(), event_packet_id::DATA_DESCRIPTOR_CHANGED); -} - -TEST_F(SignalGeneratorTest, StepSignal) -{ - const size_t packetSize = 100; - - auto expectedSamples1 = calculateExpectedSamples(0, packetSize, stepFunction10); - auto expectedSamples2 = calculateExpectedSamples(packetSize, packetSize, stepFunction10); - - auto reader = PacketReader(signal); - - auto generator = SignalGenerator(signal, std::chrono::system_clock::now()); - generator.setFunction(stepFunction10); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize)); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize * 2)); - - auto packets = reader.readAll(); - ASSERT_EQ(packets.getCount(), 3u); - - auto packet1 = packets[1].asPtr(); - ASSERT_EQ(packet1.getSampleCount(), packetSize); - ASSERT_TRUE(compareSamples(expectedSamples1.data(), packet1.getData(), packetSize)); - - auto packet2 = packets[2].asPtr(); - ASSERT_EQ(packet2.getSampleCount(), packetSize); - ASSERT_TRUE(compareSamples(expectedSamples2.data(), packet2.getData(), packetSize)); -} - -TEST_F(SignalGeneratorTest, ChangeFunction) -{ - const size_t packetSize = 100; - - auto expectedSamples1 = calculateExpectedSamples(0, packetSize, stepFunction10); - auto expectedSamples2 = calculateExpectedSamples(packetSize, packetSize, stepFunction100); - - auto reader = PacketReader(signal); - - auto updateFunction = [this](SignalGenerator& generator, uint64_t packetOffset) - { - if (packetOffset > 0) - generator.setFunction(stepFunction100); - }; - - auto generator = SignalGenerator(signal, std::chrono::system_clock::now()); - generator.setFunction(stepFunction10); - generator.setUpdateFunction(updateFunction); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize)); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize * 2)); - - auto packets = reader.readAll(); - ASSERT_EQ(packets.getCount(), 3u); - - auto packet1 = packets[1].asPtr(); - ASSERT_EQ(packet1.getSampleCount(), packetSize); - ASSERT_TRUE(compareSamples(expectedSamples1.data(), packet1.getData(), packetSize)); - - auto packet2 = packets[2].asPtr(); - ASSERT_EQ(packet2.getSampleCount(), packetSize); - ASSERT_TRUE(compareSamples(expectedSamples2.data(), packet2.getData(), packetSize)); -} - -TEST_F(SignalGeneratorTest, SignalGeneratorCountCheck) -{ - const size_t packetSize= 100; - auto expectedSamples1 = calculateExpectedSamples(0, packetSize, stepFunction10); - - auto reader = PacketReader(signal); - - auto generator = SignalGenerator(signal, std::chrono::system_clock::now()); - generator.setFunction(stepFunction10); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize)); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize * 2)); - generator.generateSamplesTo(std::chrono::milliseconds(packetSize * 3)); - - auto packets = reader.readAll(); - ASSERT_EQ(packets.getCount(), 4u); - auto packet1 = packets[1].asPtr(); - ASSERT_EQ(packet1.getSampleCount(), packetSize); - auto packet2 = packets[2].asPtr(); - ASSERT_EQ(packet2.getSampleCount(), packetSize); -} diff --git a/shared/libraries/websocket_streaming/tests/test_websocket_client_device.cpp b/shared/libraries/websocket_streaming/tests/test_websocket_client_device.cpp index 6d00ead..7c23803 100644 --- a/shared/libraries/websocket_streaming/tests/test_websocket_client_device.cpp +++ b/shared/libraries/websocket_streaming/tests/test_websocket_client_device.cpp @@ -20,10 +20,17 @@ class WebsocketClientDeviceTest : public testing::Test const uint16_t CONTROL_PORT = daq::streaming_protocol::HTTP_CONTROL_PORT; const std::string HOST = "127.0.0.1"; ContextPtr context; + DeviceTypePtr deviceType; void SetUp() override { context = NullContext(); + deviceType = DeviceTypeBuilder() + .setId("OpenDAQLTStreaming") + .setName("Streaming LT enabled pseudo-device") + .setDescription("Pseudo device, provides only signals of the remote device as flat list") + .setConnectionStringPrefix("daq.lt") + .build(); } void TearDown() override @@ -33,7 +40,7 @@ class WebsocketClientDeviceTest : public testing::Test TEST_F(WebsocketClientDeviceTest, CreateWithInvalidParameters) { - ASSERT_THROW(WebsocketClientDevice(context, nullptr, "device", nullptr), ArgumentNullException); + ASSERT_THROW(WebsocketClientDevice(context, nullptr, "device", nullptr, deviceType), ArgumentNullException); } TEST_F(WebsocketClientDeviceTest, CreateSuccess) @@ -48,7 +55,7 @@ TEST_F(WebsocketClientDeviceTest, CreateSuccess) server.start(); DevicePtr clientDevice; - ASSERT_NO_THROW(clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST)); + ASSERT_NO_THROW(clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType)); } TEST_F(WebsocketClientDeviceTest, DeviceInfo) @@ -63,7 +70,7 @@ TEST_F(WebsocketClientDeviceTest, DeviceInfo) server.start(); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); // get DeviceInfo and check fields DeviceInfoPtr clientDeviceInfo; @@ -158,7 +165,7 @@ TEST_P(WebsocketClientDeviceTestP, SignalWithDomain) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); if (signalsAddedAfterConnect) @@ -244,7 +251,7 @@ TEST_P(WebsocketClientDeviceTestP, SingleDomainSignal) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); if (signalsAddedAfterConnect) @@ -280,7 +287,7 @@ TEST_P(WebsocketClientDeviceTestP, SingleUnsupportedSignal) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); if (signalsAddedAfterConnect) @@ -317,7 +324,7 @@ TEST_P(WebsocketClientDeviceTestP, SignalsWithSharedDomain) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); if (signalsAddedAfterConnect) @@ -378,7 +385,7 @@ TEST_F(WebsocketClientDeviceTest, ChangeValueDescriptorToSupported) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); auto valueSignal = clientDevice.getSignals()[0].asPtr(); @@ -472,7 +479,7 @@ TEST_P(UnsupportedSignalsTestP, MakeValueSignalUnsupported) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); auto valueSignal = clientDevice.getSignals()[0].asPtr(); @@ -540,7 +547,7 @@ TEST_P(UnsupportedSignalsTestP, MakeDomainSignalUnsupported) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); auto valueSignal = clientDevice.getSignals()[0].asPtr(); auto domainSignal = clientDevice.getSignals()[1].asPtr(); @@ -613,7 +620,7 @@ TEST_P(UnsupportedSignalsTestP, MakeValueSignalSupported) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); ASSERT_EQ(clientDevice.getSignals().getCount(), 2u); @@ -680,7 +687,7 @@ TEST_P(UnsupportedSignalsTestP, MakeDomainSignalSupported) server->start(STREAMING_PORT, CONTROL_PORT); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); clientDevice.asPtr().enableCoreEventTrigger(); ASSERT_EQ(clientDevice.getSignals().getCount(), 2u); @@ -745,7 +752,7 @@ TEST_F(WebsocketClientDeviceTest, DeviceWithMultipleSignals) server.start(); // Create the client device - auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST); + auto clientDevice = WebsocketClientDevice(NullContext(), nullptr, "device", HOST, deviceType); // There should not be any difference if we get signals recursively or not, // since client device doesn't know anything about hierarchy diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..f1a22ca --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +opendaq_set_cmake_folder_context(TARGET_FOLDER_NAME) + +if (MSVC) + add_compile_options(/wd4100) +endif() + +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif() + +if (${REPO_OPTION_PREFIX}_ENABLE_SIGGEN_INTEGRATION_TESTS) + message(STATUS "Websocket streaming signal generator tool integration test app") + add_subdirectory(test_ws_siggen_integration) +endif() diff --git a/tests/test_ws_siggen_integration/CMakeLists.txt b/tests/test_ws_siggen_integration/CMakeLists.txt new file mode 100644 index 0000000..6512ed9 --- /dev/null +++ b/tests/test_ws_siggen_integration/CMakeLists.txt @@ -0,0 +1,41 @@ +set(TEST_APP test_siggen_integration) + +set(TEST_SOURCES test_websocket_siggen.cpp + test_app.cpp +) + +add_executable(${TEST_APP} ${TEST_SOURCES} +) + +target_link_libraries(${TEST_APP} PRIVATE daq::opendaq_test_utils gtest + daq::opendaq +) + +add_dependencies(${TEST_APP} daq::ws_stream_cl_module + siggen2websocket + siggen2socket +) + +find_program(BASH_PROGRAM bash) +if(BASH_PROGRAM) + message(STATUS "Bash found - add siggen test") + set(TEST_SCRIPT "\ + $ 7413 ${CMAKE_CURRENT_SOURCE_DIR}/siggen_config.json 1>/tmp/siggen2websocket_output 2>/tmp/siggen2websocket_output 0 7411 ${CMAKE_CURRENT_SOURCE_DIR}/siggen_config.json 1>/tmp/siggen2socket_output 2>/tmp/siggen2socket_output 0; \ + EXIT_CODE=$?; \ + killall siggen2websocket; \ + killall siggen2socket; \ + echo \"\nsiggen2websocket output:\n\n$() diff --git a/tests/test_ws_siggen_integration/siggen_config.json b/tests/test_ws_siggen_integration/siggen_config.json new file mode 100644 index 0000000..efec808 --- /dev/null +++ b/tests/test_ws_siggen_integration/siggen_config.json @@ -0,0 +1,36 @@ +{ + "signals" : { + "Signal1_Sync" : { + "dataType" : "real64", + "function" : "impulse", + "amplitude" : 5, + "offset" : 0, + "frequency" : 2, + "samplePeriod" : "10ms", + "explicitTime": false, + "range" : { + "low" : -15, + "high" : 15 + } + }, + "Signal2_Sync_PostScaling" : { + "dataType" : "int32", + "function" : "impulse", + "amplitude" : 5, + "offset" : 0, + "frequency" : 2, + "samplePeriod" : "10ms", + "explicitTime": false, + "range" : { + "low" : -15, + "high" : 15 + }, + "postScaling" : { + "scale" : 2, + "offset" : 5 + } + } + }, + "executionTime": "100s", + "processPeriod": "100ms" +} diff --git a/tests/test_ws_siggen_integration/test_app.cpp b/tests/test_ws_siggen_integration/test_app.cpp new file mode 100644 index 0000000..8cf7850 --- /dev/null +++ b/tests/test_ws_siggen_integration/test_app.cpp @@ -0,0 +1,14 @@ +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + auto res = RUN_ALL_TESTS(); + + return res; +} diff --git a/tests/test_ws_siggen_integration/test_websocket_siggen.cpp b/tests/test_ws_siggen_integration/test_websocket_siggen.cpp new file mode 100644 index 0000000..49e56a0 --- /dev/null +++ b/tests/test_ws_siggen_integration/test_websocket_siggen.cpp @@ -0,0 +1,145 @@ +#include +#include +#include "testutils/memcheck_listener.h" +#include +#include + +using SiggenTest = testing::TestWithParam; + +using namespace daq; + +static InstancePtr CreateClientInstance(std::string connectionString) +{ + auto instance = Instance(); + auto refDevice = instance.addDevice(connectionString); + return instance; +} + +// signals configuration is set by "siggen_config.json" + +TEST_P(SiggenTest, ConnectAndDisconnect) +{ + auto client = CreateClientInstance(GetParam()); +} + +TEST_P(SiggenTest, GetRemoteDeviceObjects) +{ + auto client = CreateClientInstance(GetParam()); + + ASSERT_EQ(client.getDevices().getCount(), 1u); + auto signals = client.getSignalsRecursive(); + ASSERT_EQ(signals.getCount(), 4u); +} + +TEST_P(SiggenTest, SyncSignalDescriptors) +{ + auto client = CreateClientInstance(GetParam()); + + auto signal = client.getSignalsRecursive()[0]; + + EXPECT_EQ(signal.getLocalId(), "Signal1_Sync"); + + DataDescriptorPtr dataDescriptor = signal.getDescriptor(); + DataDescriptorPtr domainDescriptor = signal.getDomainSignal().getDescriptor(); + + EXPECT_EQ(signal.getName(), "value"); + + EXPECT_EQ(dataDescriptor.getSampleType(), SampleType::Float64); + EXPECT_EQ(dataDescriptor.getRule().getType(), DataRuleType::Explicit); + EXPECT_EQ(dataDescriptor.getValueRange(), Range(-15, 15)); + + EXPECT_FALSE(dataDescriptor.getPostScaling().assigned()); + + EXPECT_EQ(dataDescriptor.getDimensions().getCount(), 0u); + EXPECT_EQ(dataDescriptor.getMetadata().getCount(), 0u); + EXPECT_FALSE(dataDescriptor.getUnit().assigned()); + + EXPECT_EQ(domainDescriptor.getRule().getType(), DataRuleType::Linear); + EXPECT_EQ(domainDescriptor.getUnit().getSymbol(), "s"); + EXPECT_EQ(domainDescriptor.getUnit().getQuantity(), "time"); + EXPECT_NE(domainDescriptor.getOrigin(), ""); + EXPECT_NE(domainDescriptor.getTickResolution().getNumerator(), 0); + EXPECT_NE(domainDescriptor.getTickResolution().getDenominator(), 0); +} + +TEST_P(SiggenTest, SyncPostScalingSignalDescriptors) +{ + auto client = CreateClientInstance(GetParam()); + + auto signal = client.getSignalsRecursive()[1]; + + EXPECT_EQ(signal.getLocalId(), "Signal2_Sync_PostScaling"); + + DataDescriptorPtr dataDescriptor = signal.getDescriptor(); + DataDescriptorPtr domainDescriptor = signal.getDomainSignal().getDescriptor(); + + EXPECT_EQ(signal.getName(), "value"); + + EXPECT_EQ(dataDescriptor.getSampleType(), SampleType::Float64); + EXPECT_EQ(dataDescriptor.getRule().getType(), DataRuleType::Explicit); + EXPECT_EQ(dataDescriptor.getValueRange(), Range(-15, 15)); + + ASSERT_TRUE(dataDescriptor.getPostScaling().assigned()); + EXPECT_EQ(dataDescriptor.getPostScaling().getParameters().get("scale"), 2); + EXPECT_EQ(dataDescriptor.getPostScaling().getParameters().get("offset"), 5); + + EXPECT_EQ(dataDescriptor.getDimensions().getCount(), 0u); + EXPECT_EQ(dataDescriptor.getMetadata().getCount(), 0u); + EXPECT_FALSE(dataDescriptor.getUnit().assigned()); + + EXPECT_EQ(domainDescriptor.getRule().getType(), DataRuleType::Linear); + EXPECT_EQ(domainDescriptor.getUnit().getSymbol(), "s"); + EXPECT_EQ(domainDescriptor.getUnit().getQuantity(), "time"); + EXPECT_NE(domainDescriptor.getOrigin(), ""); + EXPECT_NE(domainDescriptor.getTickResolution().getNumerator(), 0); + EXPECT_NE(domainDescriptor.getTickResolution().getDenominator(), 0); +} + +TEST_P(SiggenTest, DISABLED_AsyncSignalDescriptors) +{ + auto client = CreateClientInstance(GetParam()); + + auto signal = client.getSignalsRecursive()[2]; + + EXPECT_EQ(signal.getLocalId(), "Signal2_Async"); + + DataDescriptorPtr dataDescriptor = signal.getDescriptor(); + DataDescriptorPtr domainDescriptor = signal.getDomainSignal().getDescriptor(); + + EXPECT_EQ(signal.getName(), "value"); + + EXPECT_EQ(dataDescriptor.getSampleType(), SampleType::Float64); + EXPECT_EQ(dataDescriptor.getRule().getType(), DataRuleType::Explicit); + EXPECT_EQ(dataDescriptor.getValueRange(), Range(-15, 15)); + + EXPECT_EQ(dataDescriptor.getDimensions().getCount(), 0u); + EXPECT_EQ(dataDescriptor.getMetadata().getCount(), 0u); + EXPECT_FALSE(dataDescriptor.getUnit().assigned()); + + EXPECT_EQ(domainDescriptor.getRule().getType(), DataRuleType::Explicit); + EXPECT_EQ(domainDescriptor.getUnit().getSymbol(), "s"); + EXPECT_EQ(domainDescriptor.getUnit().getQuantity(), "time"); + EXPECT_NE(domainDescriptor.getOrigin(), ""); + EXPECT_NE(domainDescriptor.getTickResolution().getNumerator(), 0); + EXPECT_NE(domainDescriptor.getTickResolution().getDenominator(), 0); +} + +TEST_P(SiggenTest, DISABLED_RenderSignals) +{ + auto client = CreateClientInstance(GetParam()); + + const auto rendererFb = client.addFunctionBlock("RefFBModuleRenderer"); + + rendererFb.getInputPorts()[0].connect(client.getSignalsRecursive()[0]); + rendererFb.getInputPorts()[1].connect(client.getSignalsRecursive()[1]); + + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); +} + +INSTANTIATE_TEST_SUITE_P( + SiggenTestGroup, + SiggenTest, + testing::Values( + "daq.lt://127.0.0.1:7413/" + ) + );