Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/ut.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Unit tests

on:
push:
branches:
- '**'

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake build-essential

- name: Configure CMake
run: |
cmake -Bbuild -DTEST_ENABLED=ON -DSAMPLE_ENABLED=ON .

- name: Build project
run: |
cmake --build build

- name: Run unit tests
run: |
./build/tests/uprof-tests --reporter JUnit::out=test-results.xml --reporter console::out=-::colour-mode=ansi --success

- name: Test report
uses: dorny/test-reporter@v2
if: ${{ !cancelled() }}
with:
name: Unit Tests
path: test-results.xml
reporter: java-junit
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)

OPTION(PROFILE_ENABLED "Whether library performs profiling operations or does nothing" ON)
OPTION(SAMPLE_ENABLED "Whether sample binary is built or not" OFF)
OPTION(TEST_ENABLED "Whether unit tests binary is built or not" OFF)
OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON)
OPTION(GPU_MONITOR_NVIDIA "Whether NVidiaMonitor class for monitoring NVidia GPUs is compiled and embedded to the library" OFF)

Expand All @@ -11,3 +12,7 @@ ADD_SUBDIRECTORY(lib)
IF(SAMPLE_ENABLED)
ADD_SUBDIRECTORY(sample)
ENDIF()

IF(TEST_ENABLED)
ADD_SUBDIRECTORY(tests)
ENDIF()
2 changes: 1 addition & 1 deletion lib/eventsfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ void EventsFile::write(const std::string& event, unsigned long long timestamp, c
string line = ss.str();

// Total size of all rotating files should never exceed the defined max cap size
std::lock_guard<std::mutex> guard(m_fileMutex);
if (m_maxCapSize > 0 && m_currentFileSize + line.size() > m_maxCapSize / ROTATING_FILES_NUMBER) {
rotateFile();
}

std::lock_guard<std::mutex> guard(m_fileMutex);
m_file << line;
m_file.flush();
m_currentFileSize += line.size();
Expand Down
27 changes: 27 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
PROJECT(uprof-tests DESCRIPTION "Unit tests")
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)

SET( CMAKE_USE_RELATIVE_PATHS ON)

INCLUDE(FetchContent)

FETCHCONTENT_DECLARE(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.8.1 # or a later release
)

FETCHCONTENT_MAKEAVAILABLE(Catch2)

LIST(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
INCLUDE(CTest)
INCLUDE(Catch)

ADD_EXECUTABLE(${PROJECT_NAME}
test.cpp
)

target_link_libraries(${PROJECT_NAME}
Catch2::Catch2WithMain
cppuprofile
)
106 changes: 106 additions & 0 deletions tests/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Software Name : cppuprofile
// SPDX-FileCopyrightText: Copyright (c) 2025 Orange
// SPDX-License-Identifier: BSD-3-Clause
//
// This software is distributed under the BSD License;
// see the LICENSE file for more details.
//
// Author: Cédric CHEDALEUX <cedric.chedaleux@orange.com> et al

#include <catch2/catch_test_macros.hpp>
#include <unistd.h>
#include <uprofile.h>

static const std::string filename = "./test.log";

bool fileExists(const std::string& filename) {
std::ifstream file(filename);
return file.is_open();
}

int fileSize(const std::string& filename) {
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file.good()) return 0;
return file.tellg();
}

TEST_CASE("Uprofile instant metrics", "[instant]")
{
uprofile::start(filename.c_str());

SECTION("Instant CPU Usage")
{
std::vector<float> loads = uprofile::getInstantCpuUsage();
for (auto it = loads.cbegin(); it != loads.cend(); ++it) {
REQUIRE(*it >= 0.);
REQUIRE(*it <= 100.0);
}
}

SECTION("No update in the file")
{
std::ifstream file(filename, std::ios::binary | std::ios::ate);
REQUIRE(file.good());
REQUIRE(file.tellg() == 0);
file.close();
sleep(1);
file.open(filename, std::ios::binary | std::ios::ate);
REQUIRE(file.tellg() == 0);
}

uprofile::stop();
std::remove(filename.c_str());
}

TEST_CASE("Uprofile monitoring metrics", "[monitoring]")
{
uprofile::start(filename.c_str());
uprofile::startCPUUsageMonitoring(200);
SECTION("File existency")
{
REQUIRE( fileExists(filename) );
}

SECTION("File update")
{
// Check that the file grows over time
auto size = fileSize(filename);
sleep(1);
REQUIRE(fileSize(filename) > size);
}
uprofile::stop();
std::remove(filename.c_str());
}

TEST_CASE("Uprofile rotating files", "[rotation]")
{
// The two rotating files will have a maximum of 100 bytes in total
int maxSize = 100; // bytes
uprofile::start(filename.c_str(), maxSize);

// Enable all monitoring to stress the library
uprofile::startCPUUsageMonitoring(50);
uprofile::startSystemMemoryMonitoring(50);
uprofile::startProcessMemoryMonitoring(50);

size_t pos = filename.rfind('.');
std::string file1 = filename;
std::string file2 = filename;
file1.insert(pos,"_0");
file2.insert(pos,"_1");

SECTION("Two rotating files")
{
// Wait a couple of seconds to have several rotations
sleep(2);
REQUIRE( fileExists(file1) );
REQUIRE( fileExists(file2) );

// Check total size does not exceed the limit
REQUIRE (fileSize(file1) + fileSize(file2) < maxSize);
}

uprofile::stop();
std::remove(file1.c_str());
std::remove(file2.c_str());
}