Adds possibility to change log level of logs sent to collectors.
Test: Run nice-lad-tests
Change-Id: I95b5f238fac3bd935ae96417f4c8ea3d71825649
Signed-off-by: Oskar Świtalski <o.switalski@samsung.com>
+# This file controls the configuration of the nice-lad plugin.
+# It simply takes events and writes them to a syslog or journald.
+# This plugin can take 1 argument, the -l LOG_LEVEL, where possible
+# log levels are defined in syslog(3).
+
active = yes
direction = out
path = @SBIN_DIR@/nice-lad
type = always
+# args = -l LOG_INFO
#
# @file src/CMakeLists.txt
# @author Aleksander Zdyb <a.zdyb@samsung.com>
+# @author Oskar Świtalski <o.switalski@samsung.com>
#
OPTION(WITH_SECURITY_MANAGER "Use Security Manager to obtain resource groups" OFF)
ADD_DEFINITIONS("-DWITH_SECURITY_MANAGER")
ENDIF(WITH_SECURITY_MANAGER)
-FIND_PACKAGE(Boost 1.57 REQUIRED)
+FIND_PACKAGE(Boost 1.57 REQUIRED program_options)
PKG_CHECK_MODULES(audit
REQUIRED
Audit/SyscallRuleData.cpp
Lad/AuditEventHandler.cpp
Lad/AuditRulesPopulator.cpp
+ Lad/CollectorLogLevelSetter.cpp
+ Lad/CommandlineProcessor.cpp
+ Lad/DataCollector.cpp
Lad/Options.cpp
Log/log.cpp
Utils/Feed.cpp
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/BaseCollectorLogLevelSetter.h
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Declaration of abstract class for setting collector log level
+ */
+
+#ifndef SRC_LAD_BASECOLLECTORLOGLEVELSETTER_H
+#define SRC_LAD_BASECOLLECTORLOGLEVELSETTER_H
+
+namespace Lad {
+
+class BaseCollectorLogLevelSetter {
+public:
+ virtual void changeLevel(int logLevel) = 0;
+};
+
+} /* namespace Lad */
+
+#endif // SRC_LAD_BASECOLLECTORLOGLEVELSETTER_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/CollectorLogLevelSetter.cpp
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Definition of class for setting collector log level
+ */
+
+#include "CollectorLogLevelSetter.h"
+#include "DataCollector.h"
+
+namespace Lad {
+
+void CollectorLogLevelSetter::changeLevel(int logLevel) {
+ Lad::DataCollector::setCollectorLogLevel(logLevel);
+}
+
+} /* namespace Lad */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/CollectorLogLevelSetter.h
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Declaration of class for setting collector log level
+ */
+
+#ifndef SRC_LAD_COLLECTORLOGLEVELSETTER_H
+#define SRC_LAD_COLLECTORLOGLEVELSETTER_H
+
+#include "BaseCollectorLogLevelSetter.h"
+
+namespace Lad {
+
+class CollectorLogLevelSetter : public BaseCollectorLogLevelSetter {
+public:
+ void changeLevel(int logLevel) override;
+};
+
+} /* namespace Lad */
+
+#endif // SRC_LAD_COLLECTORLOGLEVELSETTER_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/CommandlineProcessor.cpp
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Definition of CommandlineProcessor class
+ */
+
+#include <map>
+#include <string>
+#include <syslog.h>
+#include <vector>
+
+#include <boost/any.hpp>
+#include <boost/program_options.hpp>
+
+#include "CommandlineProcessor.h"
+
+namespace Lad {
+
+namespace Options {
+
+namespace {
+
+const std::map<std::string, int> levelMap = { { "LOG_EMERG", LOG_EMERG },
+ { "LOG_ALERT", LOG_ALERT },
+ { "LOG_CRIT", LOG_CRIT },
+ { "LOG_ERR", LOG_ERR },
+ { "LOG_WARNING", LOG_WARNING },
+ { "LOG_NOTICE", LOG_NOTICE },
+ { "LOG_INFO", LOG_INFO },
+ { "LOG_DEBUG", LOG_DEBUG } };
+
+} /* namespace */
+
+/**
+ * @brief called by Boost::program_options to validate and parse collector log level to int
+ */
+void validate(boost::any &v, const std::vector<std::string> &values, CollectorLevel *, int) {
+ namespace po = boost::program_options;
+
+ po::validators::check_first_occurrence(v);
+ const std::string &s = po::validators::get_single_string(values);
+
+ auto iter = levelMap.find(s);
+ if (iter != levelMap.end())
+ v = boost::any(CollectorLevel{std::get<1>(*iter)});
+ else
+ throw po::validation_error(po::validation_error::invalid_option_value);
+}
+
+CommandlineProcessor::CommandlineProcessor(int argc, char * const *argv) : m_argc(argc),
+ m_argv(argv) {}
+
+ExitType CommandlineProcessor::process(BaseCollectorLogLevelSetter &setter) {
+ namespace po = boost::program_options;
+
+ try {
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("collector-log-level,l", po::value<CollectorLevel>()->value_name("LOG_LEVEL"),
+ "set collector log level, possible values are: \n"
+ "LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, "
+ "LOG_INFO (default), LOG_DEBUG"
+ )
+ ;
+ po::variables_map vm;
+ po::store(parse_command_line(m_argc, m_argv, desc), vm);
+ notify(vm);
+
+ if (vm.count("help")) {
+ *m_out << desc << std::endl;
+ return ExitType::HELP;
+ }
+
+ if (vm.count("collector-log-level")) {
+ setter.changeLevel(vm["collector-log-level"].as<CollectorLevel>());
+ }
+ } catch (const po::error &e) {
+ *m_err << e.what() << std::endl;
+ return ExitType::USAGE;
+ }
+
+ return ExitType::NO_EXIT;
+}
+
+void CommandlineProcessor::setOutputStream(std::ostream *out) {
+ m_out = out;
+}
+
+void CommandlineProcessor::setErrorStream(std::ostream *err) {
+ m_err = err;
+}
+
+} /* namespace Options */
+
+} /* namespace Lad */
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/CommandlineProcessor.h
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Declaration of CommandlineProcessor class
+ */
+
+#ifndef SRC_LAD_COMMANDLINEPROCESSOR_H
+#define SRC_LAD_COMMANDLINEPROCESSOR_H
+
+#include <iostream>
+#include <ostream>
+
+#include <Lad/BaseCollectorLogLevelSetter.h>
+
+namespace Lad {
+
+namespace Options {
+
+enum class ExitType {
+ NO_EXIT,
+ HELP,
+ USAGE,
+};
+
+struct CollectorLevel {
+ operator int() const {
+ return m_level;
+ }
+ int m_level;
+};
+
+class CommandlineProcessor {
+public:
+ CommandlineProcessor(int argc, char * const *argv);
+ ExitType process(BaseCollectorLogLevelSetter &setter);
+
+ void setOutputStream(std::ostream *out);
+ void setErrorStream(std::ostream *err);
+private:
+ int m_argc;
+ char * const *m_argv;
+ std::ostream *m_out = &std::cout;
+ std::ostream *m_err = &std::cerr;
+};
+
+} /* namespace Options */
+
+} /* namespace Lad */
+
+#endif // SRC_LAD_COMMANDLINEPROCESSOR_H
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file src/Lad/DataCollector.cpp
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Definition of abstract class for sending logs to log collector
+ */
+
+#include <syslog.h>
+
+#include "DataCollector.h"
+
+int Lad::DataCollector::s_collectorLogLevel = LOG_INFO;
+
+void Lad::DataCollector::setCollectorLogLevel(int collectorLogLevel) {
+ s_collectorLogLevel = collectorLogLevel;
+}
/**
* @file src/Lad/DataCollector.h
* @author Aleksander Zdyb <a.zdyb@samsung.com>
+ * @author Oskar Świtalski <o.switalski@samsung.com>
* @version 1.0
+ * @brief Declaration of abstract class for sending logs to log collector
*/
#ifndef SRC_LAD_DATACOLLECTOR_H
public:
virtual ~DataCollector() = default;
virtual void log(const std::string &logMessage) = 0;
+
+ static void setCollectorLogLevel(int collectorLogLevel);
+protected:
+ static int s_collectorLogLevel;
};
} /* namespace Lad */
/**
* @file src/Lad/SyslogDataCollector.cpp
* @author Aleksander Zdyb <a.zdyb@samsung.com>
+ * @author Oskar Świtalski <o.switalski@samsung.com>
* @version 1.0
+ * @brief Definition of class for sending logs to syslog
*/
#include <syslog.h>
namespace Lad {
void SyslogDataCollector::log(const std::string &logMessage) {
- syslog(LOG_INFO, "%s", logMessage.c_str());
+ syslog(s_collectorLogLevel, "%s", logMessage.c_str());
}
} /* namespace Lad */
* @file src/Lad/SyslogDataCollector.h
* @author Aleksander Zdyb <a.zdyb@samsung.com>
* @version 1.0
+ * @brief Declaration of class for sending logs to syslog
*/
#ifndef SRC_LAD_SYSLOGDATACOLLECTOR_H
public:
virtual ~SyslogDataCollector() = default;
- virtual void log(const std::string &logMessage);
+ void log(const std::string &logMessage) override;
};
} /* namespace Lad */
/**
* @file src/Systemd/DataCollector.cpp
* @author Aleksander Zdyb <a.zdyb@samsung.com>
+ * @author Oskar Świtalski <o.switalski@samsung.com>
* @version 1.0
+ * @brief Definition of class for sending logs to journald
*/
#include <systemd/sd-journal.h>
namespace Systemd {
void DataCollector::log(const std::string &logMessage) {
- sd_journal_print(LOG_INFO, "%s", logMessage.c_str());
+ sd_journal_print(s_collectorLogLevel, "%s", logMessage.c_str());
}
* @file src/Systemd/DataCollector.h
* @author Aleksander Zdyb <a.zdyb@samsung.com>
* @version 1.0
+ * @brief Declaration of class for sending logs to journald
*/
#ifndef SRC_SYSTEMD_DATACOLLECTOR_H
using Lad::DataCollector::DataCollector;
virtual ~DataCollector() = default;
- virtual void log(const std::string &logMessage);
+ void log(const std::string &logMessage) override;
};
} /* namespace Systemd */
/**
* @file src/main.cpp
* @author Aleksander Zdyb <a.zdyb@samsung.com>
+ * @author Oskar Świtalski <o.switalski@samsung.com>
* @version 1.0
+ * @brief Main file for nice-lad
*/
#include <csignal>
#include <Audit/Parser.h>
#include <Lad/AuditEventHandler.h>
#include <Lad/AuditRulesPopulator.h>
+#include <Lad/CollectorLogLevelSetter.h>
+#include <Lad/CommandlineProcessor.h>
#include <Lad/Options.h>
#include <Log/log.h>
#include <Utils/Feed.h>
LOGI("Starting nice-lad");
try {
+ Lad::CollectorLogLevelSetter collectorLogLevelSetter;
+ Lad::Options::CommandlineProcessor commandlineProcessor(argc, argv);
+
+ auto processCommandLineReturn = commandlineProcessor.process(collectorLogLevelSetter);
+
+ switch (processCommandLineReturn) {
+ case Lad::Options::ExitType::HELP:
+ return EXIT_SUCCESS;
+ case Lad::Options::ExitType::USAGE:
+ LOGE("Improper use of command line options (Terminating)");
+ return EXIT_FAILURE;
+ default:
+ break;
+ }
+
Audit::AuditWrapper auditApi;
Audit::AuparseSourceFeedWrapper auparseApi;
Audit::Parser auParser(auparseApi);
LOGD("nice-lad up and ready");
- feed.start();
+ feed.start();
} catch (const std::exception &ex) {
LOGC(ex.what() << " (Terminating)");
return EXIT_FAILURE;
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file tests/BaseCommandlineTest.h
+ * @author Aleksander Zdyb <a.zdyb@samsung.com>
+ * @author Pawel Wieczorek <p.wieczorek2@samsung.com>
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Base fixture for tests of commandline parsers
+ */
+
+#ifndef TESTS_BASECOMMANDLINETEST_H
+#define TESTS_BASECOMMANDLINETEST_H
+
+#include <cstdlib>
+#include <cstring>
+#include <new>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+class BaseCommandlineTest : public ::testing::Test {
+public:
+ typedef std::vector<std::string> Args;
+
+ void prepare_argv(const Args &args) {
+ destroy_argv();
+
+ m_argc = args.size();
+ m_argv = new char*[m_argc]();
+
+ for (auto i = 0; i < m_argc; ++i) {
+ m_argv[i] = strdup(args.at(i).c_str());
+ if (m_argv[i] == nullptr)
+ throw std::bad_alloc();
+ }
+ }
+
+ int argc(void) const {
+ return m_argc;
+ }
+
+ char * const *argv(void) const {
+ return m_argv;
+ }
+
+protected:
+ void TearDown(void) override {
+ destroy_argv();
+ }
+
+ void destroy_argv(void) {
+ for (auto i = 0; i < m_argc; ++i) {
+ free(m_argv[i]);
+ }
+ delete[] m_argv;
+
+ m_argc = 0;
+ m_argv = nullptr;
+ }
+
+ int m_argc = 0;
+ char **m_argv = nullptr;
+};
+
+#endif /* TESTS_BASECOMMANDLINETEST_H_ */
#
# @file tests/CMakeLists.txt
# @author Aleksander Zdyb <a.zdyb@samsung.com>
+# @author Oskar Świtalski <o.switalski@samsung.com>
#
-FIND_PACKAGE(Boost 1.57 REQUIRED)
+FIND_PACKAGE(Boost 1.57 REQUIRED program_options)
FIND_PACKAGE(Threads REQUIRED) # Required by gmock
)
ENDIF(NOT gmock_FOUND)
-SET(LAD_SRC_DIR ../src)
+SET(LAD_SRC_DIR ${PROJECT_SOURCE_DIR}/src)
INCLUDE_DIRECTORIES(
${audit_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${gmock_INCLUDE_DIRS}
${LAD_SRC_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
)
SET(SOURCE_FILES
Audit/parser.cpp
Audit/syscall_rule_data.cpp
Lad/audit_event_handler.cpp
+ Lad/process_command_line.cpp
SecurityManager/data_provider.cpp
Utils/with_message_exception.cpp
${LAD_SRC_DIR}/Audit/Parser.cpp
${LAD_SRC_DIR}/Audit/SyscallRuleData.cpp
${LAD_SRC_DIR}/Lad/AuditEventHandler.cpp
+ ${LAD_SRC_DIR}/Lad/CommandlineProcessor.cpp
+ ${LAD_SRC_DIR}/Lad/DataCollector.cpp
+ ${LAD_SRC_DIR}/Lad/DummyDataProvider.cpp
+ ${LAD_SRC_DIR}/Lad/Options.cpp
+ ${LAD_SRC_DIR}/Lad/SyslogDataCollector.cpp
${LAD_SRC_DIR}/Log/log.cpp
${LAD_SRC_DIR}/SecurityManager/DataProvider.cpp
)
${CMAKE_THREAD_LIBS_INIT}
${gmock_LDFLAGS}
${gmock_LIBRARIES}
+ ${Boost_LIBRARIES}
)
ELSE(gmock_FOUND)
TARGET_LINK_LIBRARIES(${TARGET_NICE_LAD_TESTS}
${CMAKE_THREAD_LIBS_INIT}
+ ${Boost_LIBRARIES}
gmock gtest
)
ENDIF(gmock_FOUND)
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+/**
+ * @file tests/Lad/process_command_line.cpp
+ * @author Oskar Świtalski <o.switalski@samsung.com>
+ * @version 1.0
+ * @brief Tests for CommandlineProcessor class
+ */
+
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+#include <syslog.h>
+#include <vector>
+
+#include <boost/any.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <BaseCommandlineTest.h>
+#include <Lad/BaseCollectorLogLevelSetter.h>
+#include <Lad/CommandlineProcessor.h>
+
+namespace {
+ std::map<std::string, int> levelMap = { { "LOG_EMERG", LOG_EMERG },
+ { "LOG_ALERT", LOG_ALERT },
+ { "LOG_CRIT", LOG_CRIT },
+ { "LOG_ERR", LOG_ERR },
+ { "LOG_WARNING", LOG_WARNING },
+ { "LOG_NOTICE", LOG_NOTICE },
+ { "LOG_INFO", LOG_INFO },
+ { "LOG_DEBUG", LOG_DEBUG } };
+
+ const char *help_not_printed = "help message was not printed";
+ const char *error_not_printed = "error message was not printed";
+ const char *printed_to_output_stream = "should not print to output stream";
+ const char *printed_to_error_stream = "should not print to error stream";
+
+ const char *file_path = "./nice-lad";
+ const char *long_log_level_option = "--collector-log-level";
+ const char *log_level_option = "-l";
+ const char *long_help_option = "--help";
+ const char *help_option = "-h";
+ const char *unknown_log_level_option = "unknown_log_level";
+ const char *unrecognized_option = "--unrecognized_option";
+} /* namespace anonymous */
+
+class FakeCollectorLogLevelSetter : public Lad::BaseCollectorLogLevelSetter {
+public:
+ MOCK_METHOD1(changeLevel, void(int level));
+};
+
+class CommandLineProcessingTest : public BaseCommandlineTest {
+public:
+ /**
+ * @brief Process cmd line option, check if error msg was printed, log level was not changed
+ * and USAGE was returned
+ */
+ void failingTest() {
+ FakeCollectorLogLevelSetter logLevelSetter;
+ Lad::Options::CommandlineProcessor processor(argc(), argv());
+ processor.setErrorStream(&m_err);
+ processor.setOutputStream(&m_out);
+ ASSERT_EQ(Lad::Options::ExitType::USAGE, processor.process(logLevelSetter));
+ ASSERT_EQ(0, m_out.rdbuf()->in_avail()) << printed_to_output_stream;
+ ASSERT_LT(0, m_err.rdbuf()->in_avail()) << error_not_printed;
+ }
+
+ /**
+ * @brief Process cmd line option, check if help msg was printed, log level was not changed
+ * and HELP was returned
+ */
+ void helpMsgTest() {
+ FakeCollectorLogLevelSetter logLevelSetter;
+ Lad::Options::CommandlineProcessor processor(argc(), argv());
+ processor.setErrorStream(&m_err);
+ processor.setOutputStream(&m_out);
+ ASSERT_EQ(Lad::Options::ExitType::HELP, processor.process(logLevelSetter));
+ ASSERT_LT(0, m_out.rdbuf()->in_avail()) << help_not_printed;
+ ASSERT_EQ(0, m_err.rdbuf()->in_avail()) << printed_to_error_stream;
+ }
+
+ /**
+ * @brief Process cmd line option, check if nothing was printed, log level was correctly
+ * changed and NO_EXIT was returned
+ */
+ void changeTest(int expectedLogLevel) {
+ FakeCollectorLogLevelSetter logLevelSetter;
+ Lad::Options::CommandlineProcessor processor(argc(), argv());
+ processor.setErrorStream(&m_err);
+ processor.setOutputStream(&m_out);
+ EXPECT_CALL(logLevelSetter, changeLevel(expectedLogLevel));
+ ASSERT_EQ(Lad::Options::ExitType::NO_EXIT, processor.process(logLevelSetter));
+ ASSERT_EQ(0, m_out.rdbuf()->in_avail()) << printed_to_output_stream;
+ ASSERT_EQ(0, m_err.rdbuf()->in_avail()) << printed_to_error_stream;
+ }
+
+ /**
+ * Process cmd line options, check if nothing was printed, log level was not changed and
+ * NO_EXIT was returned
+ */
+ void noChangeTest() {
+ FakeCollectorLogLevelSetter logLevelSetter;
+ Lad::Options::CommandlineProcessor processor(argc(), argv());
+ processor.setErrorStream(&m_err);
+ processor.setOutputStream(&m_out);
+ ASSERT_EQ(Lad::Options::ExitType::NO_EXIT,
+ processor.process(logLevelSetter));
+ ASSERT_EQ(0, m_out.rdbuf()->in_avail()) << printed_to_output_stream;
+ ASSERT_EQ(0, m_err.rdbuf()->in_avail()) << printed_to_error_stream;
+ }
+
+protected:
+ void TearDown() override {
+ clearStreams();
+ BaseCommandlineTest::TearDown();
+ }
+
+ void clearStreams() {
+ m_out.clear();
+ m_out.str("");
+
+ m_err.clear();
+ m_err.str("");
+ }
+
+ std::stringstream m_out;
+ std::stringstream m_err;
+};
+
+/**
+ * @brief Test processCommandline with all correct arguments for -l option
+ * @test Scenario:
+ * - pass -l option with valid log level value
+ */
+TEST_F(CommandLineProcessingTest, validate_function) {
+ for (auto &levelPair : levelMap) {
+ SCOPED_TRACE("level = \"" + std::get<0>(levelPair) + "\"");
+ prepare_argv({ file_path, log_level_option, std::get<0>(levelPair)});
+ changeTest(std::get<1>(levelPair));
+ clearStreams();
+ destroy_argv();
+ }
+}
+
+/**
+ * @brief Test processCommandline with empty options
+ * @test Scenario:
+ * - pass nothing to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, empty_options) {
+ prepare_argv({ file_path });
+ noChangeTest();
+}
+
+/**
+ * @brief Test processCommandline with unrecognized option
+ * @test Scenario:
+ * - pass unrecognized option to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, unrecognized_option) {
+ prepare_argv({ file_path, unrecognized_option });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with no argument for -l option
+ * @test Scenario:
+ * - pass for -l option with no argument
+ */
+TEST_F(CommandLineProcessingTest, empty_log_level_option) {
+ prepare_argv({ file_path, log_level_option });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with invalid argument for -l option
+ * @test Scenario:
+ * - pass "-l unknown_log_level_option" to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, unknown_log_level_option) {
+ prepare_argv({ file_path, log_level_option, unknown_log_level_option });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with -h option
+ * @test Scenario:
+ * - pass "-h" to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, help_option) {
+ prepare_argv({ file_path, help_option });
+ helpMsgTest();
+}
+
+/**
+ * @brief Test processCommandline with --help option
+ * @test Scenario:
+ * - pass "--help" to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, long_help_option) {
+ prepare_argv({ file_path, long_help_option });
+ helpMsgTest();
+}
+
+/**
+ * @brief Test processCommandline with multiple -l specified
+ * @test Scenario:
+ * - pass multiple correct log levels to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, multiple_collector_log_level_option) {
+ prepare_argv({ file_path, log_level_option, "LOG_INFO", log_level_option, "LOG_DEBUG" });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with all correct arguments for --collector-log-level option
+ * @test Scenario:
+ * - pass --collector-log-level option with valid log level value
+ */
+TEST_F(CommandLineProcessingTest, validate_function_long) {
+ for (auto &levelPair : levelMap) {
+ SCOPED_TRACE("level = \"" + std::get<0>(levelPair) + "\"");
+ prepare_argv({ file_path, long_log_level_option, std::get<0>(levelPair)});
+ changeTest(std::get<1>(levelPair));
+ clearStreams();
+ destroy_argv();
+ }
+}
+
+/**
+ * @brief Test processCommandline with no argument for --collector-log-level option
+ * @test Scenario:
+ * - pass for --collector-log-level option with no argument
+ */
+TEST_F(CommandLineProcessingTest, empty_collector_log_level_option) {
+ prepare_argv({ file_path, long_log_level_option });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with invalid argument for --collector-log-level option
+ * @test Scenario:
+ * - pass "--collector-log-level unknown_log_level" to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, unknown_collector_log_level_option) {
+ prepare_argv({ file_path, long_log_level_option, unknown_log_level_option });
+ failingTest();
+}
+
+/**
+ * @brief Test processCommandline with multiple --collector-log-level specified
+ * @test Scenario:
+ * - pass multiple correct log levels to processCommandline
+ */
+TEST_F(CommandLineProcessingTest, multiple_collector_long_log_level_option) {
+ prepare_argv({ file_path, long_log_level_option, "LOG_INFO", long_log_level_option,
+ "LOG_DEBUG" });
+ failingTest();
+}