diff --git a/tests/executeUnitTests.sh b/tests/executeUnitTests.sh
index ba98556ed69..e173b7004f3 100755
--- a/tests/executeUnitTests.sh
+++ b/tests/executeUnitTests.sh
@@ -78,7 +78,7 @@ if [ $? -ne 0 ]; then cd ../..; exit 1; fi
if [[ "$OSTYPE" == "darwin"* ]]; then
MODULES="lib vboxwrapper"
else
- MODULES="lib sched vboxwrapper"
+ MODULES="lib client sched vboxwrapper"
fi
for T in ${MODULES}; do
XML_FLAGS=""
diff --git a/tests/unit-tests/CMakeLists.txt b/tests/unit-tests/CMakeLists.txt
index f286c272c74..c3612677795 100644
--- a/tests/unit-tests/CMakeLists.txt
+++ b/tests/unit-tests/CMakeLists.txt
@@ -71,6 +71,11 @@ else()
endif()
add_subdirectory(lib)
+
+if(UNIX AND NOT APPLE)
+ add_subdirectory(client)
+endif()
+
if (NOT APPLE)
add_subdirectory(sched)
endif()
diff --git a/tests/unit-tests/client/CMakeLists.txt b/tests/unit-tests/client/CMakeLists.txt
new file mode 100644
index 00000000000..177e01585d7
--- /dev/null
+++ b/tests/unit-tests/client/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB SRCS *.cpp)
+
+LIST(APPEND SRCS "${PROJECT_SOURCE_DIR}/../../client/hostinfo_linux.cpp")
+
+add_executable(test_client ${SRCS})
+
+TARGET_LINK_LIBRARIES(test_client "${SCHED_LIB}" "${BOINC_CRYPT_LIB}" "${BOINC_LIB}" pthread GTest::gtest GTest::gtest_main)
+
+add_test(NAME test_client COMMAND test_client)
diff --git a/tests/unit-tests/client/test_hostinfo_linux.cpp b/tests/unit-tests/client/test_hostinfo_linux.cpp
new file mode 100644
index 00000000000..236eaa2f0b0
--- /dev/null
+++ b/tests/unit-tests/client/test_hostinfo_linux.cpp
@@ -0,0 +1,71 @@
+// This file is part of BOINC.
+// https://boinc.berkeley.edu
+// Copyright (C) 2026 University of California
+//
+// BOINC is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// BOINC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with BOINC. If not, see .
+
+#include "gtest/gtest.h"
+#include "hostinfo.h"
+
+#include
+#include
+
+namespace test_hostinfo_linux {
+ class test_hostinfo_linux : public ::testing::Test {};
+
+ TEST_F(test_hostinfo_linux, parse_linux_os_info_lsb_release_ubuntu) {
+ std::string fixture_path(__FILE__);
+ fixture_path = fixture_path.substr(0, fixture_path.find_last_of('/')) + "/../testdata/lsb-release.ubuntu";
+
+ FILE* lsb_release = fopen(fixture_path.c_str(), "r");
+ ASSERT_NE(nullptr, lsb_release);
+
+ char os_name[256] = "", os_version[256] = "";
+ EXPECT_TRUE(HOST_INFO::parse_linux_os_info(lsb_release, lsbrelease, os_name, sizeof(os_name), os_version, sizeof(os_version)));
+ fclose(lsb_release);
+
+ EXPECT_STREQ("Ubuntu", os_name);
+ EXPECT_STREQ("Ubuntu 26.04 LTS", os_version);
+ }
+
+ TEST_F(test_hostinfo_linux, parse_linux_os_info_os_release_ubuntu) {
+ std::string fixture_path(__FILE__);
+ fixture_path = fixture_path.substr(0, fixture_path.find_last_of('/')) + "/../testdata/os-release.ubuntu";
+
+ FILE* os_release = fopen(fixture_path.c_str(), "r");
+ ASSERT_NE(nullptr, os_release);
+
+ char os_name[256] = "", os_version[256] = "";
+ EXPECT_TRUE(HOST_INFO::parse_linux_os_info(os_release, osrelease, os_name, sizeof(os_name), os_version, sizeof(os_version)));
+ fclose(os_release);
+
+ EXPECT_STREQ("Ubuntu", os_name);
+ EXPECT_STREQ("Ubuntu 26.04 LTS", os_version);
+ }
+
+ TEST_F(test_hostinfo_linux, parse_linux_os_info_os_release_openwrt) {
+ std::string fixture_path(__FILE__);
+ fixture_path = fixture_path.substr(0, fixture_path.find_last_of('/')) + "/../testdata/os-release.openwrt";
+
+ FILE* os_release = fopen(fixture_path.c_str(), "r");
+ ASSERT_NE(nullptr, os_release);
+
+ char os_name[256] = "", os_version[256] = "";
+ EXPECT_TRUE(HOST_INFO::parse_linux_os_info(os_release, osrelease, os_name, sizeof(os_name), os_version, sizeof(os_version)));
+ fclose(os_release);
+
+ EXPECT_STREQ("OpenWrt", os_name);
+ EXPECT_STREQ("OpenWrt 25.12.4", os_version);
+ }
+}
diff --git a/tests/unit-tests/testdata/lsb-release.ubuntu b/tests/unit-tests/testdata/lsb-release.ubuntu
new file mode 100644
index 00000000000..62d9e7d6aeb
--- /dev/null
+++ b/tests/unit-tests/testdata/lsb-release.ubuntu
@@ -0,0 +1,5 @@
+No LSB modules are available.
+Distributor ID: Ubuntu
+Description: Ubuntu 26.04 LTS
+Release: 26.04
+Codename: resolute
\ No newline at end of file
diff --git a/tests/unit-tests/testdata/os-release.openwrt b/tests/unit-tests/testdata/os-release.openwrt
new file mode 100644
index 00000000000..081d8bf1e52
--- /dev/null
+++ b/tests/unit-tests/testdata/os-release.openwrt
@@ -0,0 +1,20 @@
+NAME="OpenWrt"
+VERSION="25.12.4"
+ID="openwrt"
+ID_LIKE="lede openwrt"
+PRETTY_NAME="OpenWrt 25.12.4"
+VERSION_ID="25.12.4"
+HOME_URL="https://openwrt.org/"
+BUG_URL="https://bugs.openwrt.org/"
+SUPPORT_URL="https://forum.openwrt.org/"
+FIRMWARE_URL="https://downloads.openwrt.org/"
+BUILD_ID="r32933-4ccb782af7"
+OPENWRT_BOARD="mediatek/filogic"
+OPENWRT_ARCH="aarch64_cortex-a53"
+OPENWRT_TAINTS=""
+OPENWRT_DEVICE_MANUFACTURER="OpenWrt"
+OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/"
+OPENWRT_DEVICE_PRODUCT="Generic"
+OPENWRT_DEVICE_REVISION="v0"
+OPENWRT_RELEASE="OpenWrt 25.12.4 r32933-4ccb782af7"
+OPENWRT_BUILD_DATE="1778712129"
diff --git a/tests/unit-tests/testdata/os-release.ubuntu b/tests/unit-tests/testdata/os-release.ubuntu
new file mode 100644
index 00000000000..e89ba5478cc
--- /dev/null
+++ b/tests/unit-tests/testdata/os-release.ubuntu
@@ -0,0 +1,13 @@
+PRETTY_NAME="Ubuntu 26.04 LTS"
+NAME="Ubuntu"
+VERSION_ID="26.04"
+VERSION="26.04 LTS (Resolute Raccoon)"
+VERSION_CODENAME=resolute
+ID=ubuntu
+ID_LIKE=debian
+HOME_URL="https://www.ubuntu.com/"
+SUPPORT_URL="https://help.ubuntu.com/"
+BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
+PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
+UBUNTU_CODENAME=resolute
+LOGO=ubuntu-logo