diff options
Diffstat (limited to 'src/components/utils')
55 files changed, 4659 insertions, 459 deletions
diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt index bbb74dc1e1..3ebabe9043 100644 --- a/src/components/utils/CMakeLists.txt +++ b/src/components/utils/CMakeLists.txt @@ -1,56 +1,96 @@ -set(UtilsIncludeDir ${CMAKE_SOURCE_DIR}/src/components/utils/include) +# Copyright (c) 2015, Ford Motor Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of the Ford Motor Company nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +set(UTILS_INCLUDE_DIR ${COMPONENTS_DIR}/utils/include) +set(UTILS_SRC_DIR ${COMPONENTS_DIR}/utils/src) include_directories ( - ./include - ../config_profile/include - ../media_manager/include/ - ../protocol_handler/include/ + ${UTILS_INCLUDE_DIR} + ${COMPONENTS_DIR}/config_profile/include + ${COMPONENTS_DIR}/media_manager/include + ${COMPONENTS_DIR}/protocol_handler/include ${LOG4CXX_INCLUDE_DIRECTORY} ) set (SOURCES - ./src/bitstream.cc - ./src/conditional_variable_posix.cc - ./src/file_system.cc - ./src/threads/posix_thread.cc - ./src/threads/thread_manager.cc - ./src/threads/thread_validator.cc - ./src/lock_posix.cc - ./src/rwlock_posix.cc - ./src/date_time.cc - ./src/signals_linux.cc - ./src/system.cc - ./src/resource_usage.cc - ./src/appenders_loader.cc + ${UTILS_SRC_DIR}/bitstream.cc + ${UTILS_SRC_DIR}/conditional_variable_posix.cc + ${UTILS_SRC_DIR}/file_system.cc + ${UTILS_SRC_DIR}/threads/posix_thread.cc + ${UTILS_SRC_DIR}/threads/thread_delegate.cc + ${UTILS_SRC_DIR}/threads/thread_validator.cc + ${UTILS_SRC_DIR}/threads/async_runner.cc + ${UTILS_SRC_DIR}/lock_posix.cc + ${UTILS_SRC_DIR}/rwlock_posix.cc + ${UTILS_SRC_DIR}/date_time.cc + ${UTILS_SRC_DIR}/signals_linux.cc + ${UTILS_SRC_DIR}/system.cc + ${UTILS_SRC_DIR}/resource_usage.cc + ${UTILS_SRC_DIR}/appenders_loader.cc + ${UTILS_SRC_DIR}/gen_hash.cc ) if(ENABLE_LOG) list(APPEND SOURCES - ./src/push_log.cc - ./src/log_message_loop_thread.cc - ./src/logger_status.cc + ${UTILS_SRC_DIR}/push_log.cc + ${UTILS_SRC_DIR}/log_message_loop_thread.cc + ${UTILS_SRC_DIR}/logger_status.cc + ${UTILS_SRC_DIR}/auto_trace.cc + ${UTILS_SRC_DIR}/logger.cc ) endif() if (BUILD_BACKTRACE_SUPPORT) list(APPEND SOURCES - ./src/back_trace.cc + ${UTILS_SRC_DIR}/back_trace.cc ) endif() if (CMAKE_SYSTEM_NAME STREQUAL "QNX") list(APPEND SOURCES - ./src/threads/pulse_thread_delegate.cc + ${UTILS_SRC_DIR}/threads/pulse_thread_delegate.cc ) endif() add_library("Utils" SHARED ${SOURCES}) +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + list(APPEND LIBRARIES dl) +endif() + + if(ENABLE_LOG) list(APPEND LIBRARIES log4cxx -L${LOG4CXX_LIBS_DIRECTORY}) list(APPEND LIBRARIES apr-1 -L${APR_LIBS_DIRECTORY}) list(APPEND LIBRARIES aprutil-1 -L${APR_UTIL_LIBS_DIRECTORY}) - target_link_libraries("Utils" ${LIBRARIES}) ADD_DEPENDENCIES(Utils install-3rd_party_logger) endif() @@ -58,6 +98,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") target_link_libraries("Utils" pthread ${RTLIB}) endif() +target_link_libraries("Utils" ${LIBRARIES}) + if(BUILD_TESTS) add_subdirectory(test) endif() diff --git a/src/components/utils/include/utils/back_trace.h b/src/components/utils/include/utils/back_trace.h index 7f8912faf9..f2410e36bc 100644 --- a/src/components/utils/include/utils/back_trace.h +++ b/src/components/utils/include/utils/back_trace.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -61,10 +61,10 @@ class Backtrace { // Captured symbols in order from topmost stack frame to last captured std::vector<std::string> CallStack() const; - threads::Thread::Id ThreadId() const; + threads::PlatformThreadHandle ThreadId() const; private: - threads::Thread::Id thread_id_; + threads::PlatformThreadHandle thread_id_; std::vector<void*> backtrace_; }; diff --git a/src/components/utils/include/utils/bitstream.h b/src/components/utils/include/utils/bitstream.h index cba15abd8b..9bf41d187f 100644 --- a/src/components/utils/include/utils/bitstream.h +++ b/src/components/utils/include/utils/bitstream.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/include/utils/file_system.h b/src/components/utils/include/utils/file_system.h index d68ec484f9..7b69527606 100644 --- a/src/components/utils/include/utils/file_system.h +++ b/src/components/utils/include/utils/file_system.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -234,6 +234,13 @@ const std::string ConvertPathForURL(const std::string& path); */ bool CreateFile(const std::string& path); +/** + * @brief Get modification time of file + * @param path Path to file + * @return Modification time in nanoseconds + */ +uint64_t GetFileModificationTime(const std::string& path); + void remove_directory_content(const std::string& directory_name); } // namespace file_system diff --git a/src/components/utils/include/utils/gen_hash.h b/src/components/utils/include/utils/gen_hash.h new file mode 100644 index 0000000000..e4102d36db --- /dev/null +++ b/src/components/utils/include/utils/gen_hash.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_GEN_HASH_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_GEN_HASH_H_ + +#include <string> + +namespace utils { + +/** + * @brief generate random alphanumeric string of specified length + * @param size length of random string + * @return random string + */ + +const std::string gen_hash(size_t size); + +} // namespace utils + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_GEN_HASH_H_ diff --git a/src/components/utils/include/utils/helpers.h b/src/components/utils/include/utils/helpers.h new file mode 100644 index 0000000000..e616dd56c1 --- /dev/null +++ b/src/components/utils/include/utils/helpers.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_HELPERS_H +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_HELPERS_H + +/** + * These helpers allows to simplify compare strategy between some objects. + * Suppose user has some enum with value E with some numbers of possible values + * enum E {V1, V2, V3, V5}; + * So we want to know if some user-input value is belong to one of the enum's subset. + * Usually user has to do next routine + * + * E input_value = V3; + * if (input_value == V1 || input_value == V2 || input_value == V3) { + * do_some_stuff_here; + * } + * + * How it suppose to be with these helpers methods: + * + * E input_value = V3; + * if (Compare<E, EQ, ONE>(input_value, V1, V2, V3)) { + * do_some_stuff; + * } + * + * Also User is able to easily change compare startegy by using some set of + * predefined startegies. + */ +namespace helpers { + + template<typename T> + bool EQ (T what, T to) { + return what == to; + } + + template<typename T> + bool NEQ (T what, T to) { + return !EQ<T>(what, to); + } + + template<class U = bool> + bool ALL (U what, U to) { + return what && to; + } + + template<class U = bool> + bool ONE (U what, U to) { + return what || to; + } + + template <typename T, + bool (*CompareType)(T ,T), + bool (*CmpStrategy)(bool ,bool)> + bool Compare (T what, T to) { + return CompareType(what, to); + } + + template <typename T, + bool (*CompareType)(T ,T), + bool (*CmpStrategy)(bool, bool)> + bool Compare(T what, T to, T to1) { + return CmpStrategy(Compare<T, CompareType, CmpStrategy>(what, to), + Compare<T, CompareType, CmpStrategy>(what, to1)); + } + + template <typename T, + bool (*CompareType)(T ,T), + bool (*CmpStrategy)(bool, bool)> + bool Compare(T what, T to, T to1, T to2) { + return CmpStrategy(Compare<T, CompareType, CmpStrategy>(what, to, to1), + Compare<T, CompareType, CmpStrategy>(what, to2)); + } + + template <typename T, + bool (*CompareType)(T ,T), + bool (*CmpStrategy)(bool, bool)> + bool Compare(T what, T to, T to1, T to2, T to3) { + return CmpStrategy(Compare<T, CompareType, CmpStrategy>(what, to, to1, to2), + Compare<T, CompareType, CmpStrategy>(what, to3)); + } + + template <typename T, + bool (*CompareType)(T ,T), + bool (*CmpStrategy)(bool, bool)> + bool Compare(T what, T to, T to1, T to2, T to3, T to4) { + return CmpStrategy(Compare<T, CompareType, CmpStrategy>(what, to, to1, to2, to3), + Compare<T, CompareType, CmpStrategy>(what, to4)); + } +} + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_HELPERS_H diff --git a/src/components/utils/include/utils/log_message_loop_thread.h b/src/components/utils/include/utils/log_message_loop_thread.h index b23a246e13..87b6c7e531 100644 --- a/src/components/utils/include/utils/log_message_loop_thread.h +++ b/src/components/utils/include/utils/log_message_loop_thread.h @@ -37,6 +37,7 @@ #include <queue> #include <log4cxx/logger.h> +#include "utils/macro.h" #include "utils/threads/message_loop_thread.h" #include "utils/singleton.h" diff --git a/src/components/utils/include/utils/resource_usage.h b/src/components/utils/include/utils/resource_usage.h index a8fa4aa7d9..ff90b2c22f 100644 --- a/src/components/utils/include/utils/resource_usage.h +++ b/src/components/utils/include/utils/resource_usage.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * @@ -38,6 +38,7 @@ #include <sys/procfs.h> #endif +#include "utils/macro.h" #include <string> #include <iostream> @@ -120,6 +121,16 @@ class Resources { private: +#ifdef BUILD_TESTS + friend class ResourceUsagePrivateTest; + FRIEND_TEST(ResourceUsagePrivateTest, ReadStatFileTest); + FRIEND_TEST(ResourceUsagePrivateTest, GetProcInfoTest); + FRIEND_TEST(ResourceUsagePrivateTest, GetMemInfoTest); + FRIEND_TEST(ResourceUsagePrivateTest, GetStatPathTest_FileExists); + FRIEND_TEST(ResourceUsagePrivateTest, GetStatPathTest_ReadFile); + FRIEND_TEST(ResourceUsagePrivateTest, GetProcPathTest); +#endif + /* * @brief reads /proc/PID/stat file on linux * do not work on QNX ( return false, output wan't be changed ) diff --git a/src/components/utils/include/utils/signals.h b/src/components/utils/include/utils/signals.h index 28e8afd9d6..6c91836309 100644 --- a/src/components/utils/include/utils/signals.h +++ b/src/components/utils/include/utils/signals.h @@ -1,41 +1,49 @@ /* -* Copyright (c) 2014, Ford Motor Company -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following -* disclaimer in the documentation and/or other materials provided with the -* distribution. -* -* Neither the name of the Ford Motor Company nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SIGNALS_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SIGNALS_H_ +#ifdef __QNXNTO__ +typedef void (*sighandler_t) (int); +#else +#include <signal.h> +#endif + namespace utils { -bool SubscribeToTerminateSignal(void (*func)(int32_t p)); -bool ResetSubscribeToTerminateSignal(); + +bool SubscribeToTerminateSignal(sighandler_t func); +bool SubscribeToFaultSignal(sighandler_t func); + } // namespace utils #endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SIGNALS_H_ diff --git a/src/components/utils/include/utils/singleton.h b/src/components/utils/include/utils/singleton.h index d7b625e0a1..41face4f2f 100644 --- a/src/components/utils/include/utils/singleton.h +++ b/src/components/utils/include/utils/singleton.h @@ -28,7 +28,7 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. -*/ + */ #ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_ #define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_ diff --git a/src/components/utils/include/utils/stl_utils.h b/src/components/utils/include/utils/stl_utils.h index f525c6429f..70fbadbd5e 100644 --- a/src/components/utils/include/utils/stl_utils.h +++ b/src/components/utils/include/utils/stl_utils.h @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2013, Ford Motor Company +/* + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,14 +44,15 @@ template<class T> class StlCollectionDeleter { public: typedef T Collection; - StlCollectionDeleter(T* collection): collection_(collection) { + StlCollectionDeleter(T* collection) + : collection_(collection) { DCHECK(collection_); } ~StlCollectionDeleter() { - for (typename Collection::iterator i = collection_->begin(), - end = collection_->end(); - i != end; ++i) { + for (typename Collection::iterator i = collection_->begin(), end = + collection_->end(); i != end; ++i) { delete *i; + *i = NULL; } } private: @@ -62,20 +63,22 @@ template<class T> class StlMapDeleter { public: typedef T Collection; - StlMapDeleter(T* collection): collection_(collection) { + StlMapDeleter(T* collection) + : collection_(collection) { DCHECK(collection_); } ~StlMapDeleter() { - for (typename Collection::iterator i = collection_->begin(), - end = collection_->end(); - i != end; ++i) { + for (typename Collection::iterator i = collection_->begin(), end = + collection_->end(); i != end; ++i) { delete i->second; + i->second = NULL; } + } private: Collection* collection_; }; -} // namespace utils +} // namespace utils -#endif /* SRC_COMPONENTS_UTILS_INCLUDE_UTILS_STL_UTILS_H_ */ +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_STL_UTILS_H_ diff --git a/src/components/utils/include/utils/system.h b/src/components/utils/include/utils/system.h index 16bdc03673..3b34d78526 100644 --- a/src/components/utils/include/utils/system.h +++ b/src/components/utils/include/utils/system.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * @@ -76,6 +76,9 @@ class System { */ bool Execute(bool wait); + std::string command() const; + std::vector<std::string> argv() const; + private: /** * Command for executing diff --git a/src/components/utils/include/utils/threads/pulse_thread_delegate.h b/src/components/utils/include/utils/threads/pulse_thread_delegate.h index bb109bde94..207b64caaf 100644 --- a/src/components/utils/include/utils/threads/pulse_thread_delegate.h +++ b/src/components/utils/include/utils/threads/pulse_thread_delegate.h @@ -57,7 +57,7 @@ class PulseThreadDelegate : public ThreadDelegate { */ PulseThreadDelegate(); virtual void threadMain(); - virtual bool exitThreadMain(); + virtual void exitThreadMain(); protected: /** @@ -86,7 +86,7 @@ class PulseThreadDelegate : public ThreadDelegate { private: enum {PULSE_CODE = _PULSE_CODE_MINAVAIL + 1}; - bool run_; + volatile bool run_; int chid_; int coid_; }; diff --git a/src/components/utils/include/utils/threads/thread_validator.h b/src/components/utils/include/utils/threads/thread_validator.h index def1994b76..dc2d138e2e 100644 --- a/src/components/utils/include/utils/threads/thread_validator.h +++ b/src/components/utils/include/utils/threads/thread_validator.h @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2013, Ford Motor Company +/* + * Copyright (c) 2014, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,8 +67,9 @@ class SingleThreadSimpleValidator { // This method should be called in every public method // of classes being checked for absence of concurrent access void AssertRunningOnCreationThread() const; + PlatformThreadHandle creation_thread_id() const; private: - const Thread::Id creation_thread_id_; + const PlatformThreadHandle creation_thread_id_; }; @@ -91,13 +92,13 @@ class SingleThreadValidator { // Must be called prior to transferring object being validated to // another thread or when passing it back - void PassToThread(Thread::Id thread_id) const; + void PassToThread(PlatformThreadHandle thread_id) const; // This method should be called in every public method // of classes being checked for absence of unintended concurrent // access void AssertRunningOnValidThread() const; private: - mutable Thread::Id owning_thread_id_; + mutable PlatformThreadHandle owning_thread_id_; }; } // namespace threads diff --git a/src/components/utils/src/appenders_loader.cc b/src/components/utils/src/appenders_loader.cc index cbbd039060..9741bd1b8d 100644 --- a/src/components/utils/src/appenders_loader.cc +++ b/src/components/utils/src/appenders_loader.cc @@ -39,7 +39,7 @@ namespace utils { AppendersLoader appenders_loader; AppendersLoader::AppendersLoader() { - handle_ = dlopen("libappenders.so", RTLD_LAZY | RTLD_NODELETE); + handle_ = dlopen("libappenders.so", RTLD_LAZY); } AppendersLoader::~AppendersLoader() { diff --git a/src/components/utils/src/back_trace.cc b/src/components/utils/src/back_trace.cc index 23b1b4d1e9..f49c60b467 100644 --- a/src/components/utils/src/back_trace.cc +++ b/src/components/utils/src/back_trace.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -89,7 +89,7 @@ vector<string> Backtrace::CallStack() const { return callstack; } -Thread::Id Backtrace::ThreadId() const { +threads::PlatformThreadHandle Backtrace::ThreadId() const { return thread_id_; } diff --git a/src/components/utils/src/bitstream.cc b/src/components/utils/src/bitstream.cc index c616b1ae4a..ae353b44c6 100644 --- a/src/components/utils/src/bitstream.cc +++ b/src/components/utils/src/bitstream.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * diff --git a/src/components/utils/src/conditional_variable_posix.cc b/src/components/utils/src/conditional_variable_posix.cc index a89f8cab65..2928cac9db 100644 --- a/src/components/utils/src/conditional_variable_posix.cc +++ b/src/components/utils/src/conditional_variable_posix.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -83,14 +83,29 @@ void ConditionalVariable::Broadcast() { } -void ConditionalVariable::Wait(AutoLock& auto_lock) { +bool ConditionalVariable::Wait(Lock& lock) { + lock.AssertTakenAndMarkFree(); + int32_t wait_status = pthread_cond_wait(&cond_var_, + &lock.mutex_); + lock.AssertFreeAndMarkTaken(); + if (wait_status != 0) { + LOG4CXX_ERROR(logger_, "Failed to wait for conditional variable"); + return false; + } + return true; +} + +bool ConditionalVariable::Wait(AutoLock& auto_lock) { Lock& lock = auto_lock.GetLock(); lock.AssertTakenAndMarkFree(); int32_t wait_status = pthread_cond_wait(&cond_var_, &lock.mutex_); lock.AssertFreeAndMarkTaken(); - if (wait_status != 0) + if (wait_status != 0) { LOG4CXX_ERROR(logger_, "Failed to wait for conditional variable"); + return false; + } + return true; } ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( @@ -104,7 +119,6 @@ ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( (milliseconds % kMillisecondsPerSecond) * kNanosecondsPerMillisecond; wait_interval.tv_sec += wait_interval.tv_nsec / kNanosecondsPerSecond; wait_interval.tv_nsec %= kNanosecondsPerSecond; - Lock& lock = auto_lock.GetLock(); lock.AssertTakenAndMarkFree(); int32_t timedwait_status = pthread_cond_timedwait(&cond_var_, @@ -129,7 +143,6 @@ ConditionalVariable::WaitStatus ConditionalVariable::WaitFor( LOG4CXX_ERROR(logger_, "Failed to timewait for conditional variable timedwait_status: " << timedwait_status); } } - return wait_status; } diff --git a/src/components/utils/src/date_time.cc b/src/components/utils/src/date_time.cc index f190951647..42a199e0fb 100644 --- a/src/components/utils/src/date_time.cc +++ b/src/components/utils/src/date_time.cc @@ -1,49 +1,50 @@ /* -* Copyright (c) 2014, Ford Motor Company -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following -* disclaimer in the documentation and/or other materials provided with the -* distribution. -* -* Neither the name of the Ford Motor Company nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #include <sys/time.h> #include <stdint.h> #include "utils/date_time.h" + namespace date_time { -TimevalStruct DateTime::getCurrentTime() { - TimevalStruct currentTime; - timezone timeZone; + TimevalStruct DateTime::getCurrentTime() { + TimevalStruct currentTime; + timezone timeZone; - gettimeofday(¤tTime, &timeZone); + gettimeofday(¤tTime, &timeZone); - return currentTime; -} + return currentTime; + } int64_t date_time::DateTime::getSecs(const TimevalStruct &time) { return static_cast<int64_t>(time.tv_sec); @@ -100,3 +101,11 @@ TimeCompare date_time::DateTime::compareTime(const TimevalStruct &time1, const T } } // namespace date_time + +bool operator<(const TimevalStruct& time1, const TimevalStruct& time2) { + return date_time::DateTime::Less(time1, time2); +} + +bool operator==(const TimevalStruct& time1, const TimevalStruct& time2) { + return date_time::DateTime::Equal(time1, time2); +} diff --git a/src/components/utils/src/file_system.cc b/src/components/utils/src/file_system.cc index 64e021a6f1..69efcad863 100644 --- a/src/components/utils/src/file_system.cc +++ b/src/components/utils/src/file_system.cc @@ -325,10 +325,12 @@ std::vector<std::string> file_system::ListFiles( } closedir(directory); + + } + #ifdef __QNXNTO__ - delete[] direntbuffer; + delete[] direntbuffer; #endif - } return listFiles; } @@ -410,3 +412,14 @@ bool file_system::CreateFile(const std::string& path) { return true; } } + + +uint64_t file_system::GetFileModificationTime(const std::string& path) { + struct stat info; + stat(path.c_str(), &info); +#ifndef __QNXNTO__ + return static_cast<uint64_t>(info.st_mtim.tv_nsec); +#else + return static_cast<uint64_t>(info.st_mtime); +#endif +} diff --git a/src/components/utils/src/gen_hash.cc b/src/components/utils/src/gen_hash.cc new file mode 100644 index 0000000000..6ac5c217c3 --- /dev/null +++ b/src/components/utils/src/gen_hash.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils/gen_hash.h" + +#include <cstdlib> + +namespace utils { + +const std::string gen_hash(size_t size) { + static const char symbols[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static const size_t capacity = sizeof(symbols) - 1; + + std::string hash(size, '\0'); + for (std::string::iterator i = hash.begin(); i != hash.end(); ++i) { + int index = std::rand() % capacity; + *i = symbols[index]; + } + return hash; +} + +} // namespace utils diff --git a/src/components/utils/src/lock_posix.cc b/src/components/utils/src/lock_posix.cc index f75b7ee9ea..d2837708fa 100644 --- a/src/components/utils/src/lock_posix.cc +++ b/src/components/utils/src/lock_posix.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2013, Ford Motor Company * All rights reserved. * @@ -34,6 +34,8 @@ #include <errno.h> #include <stdint.h> +#include <stdio.h> +#include <string.h> #include "utils/logger.h" @@ -43,11 +45,11 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") Lock::Lock() #ifndef NDEBUG - : lock_taken_(0), - is_mutex_recursive_(false) + : lock_taken_(0), + is_mutex_recursive_(false) #endif // NDEBUG { - int32_t status = pthread_mutex_init(&mutex_, NULL); + const int32_t status = pthread_mutex_init(&mutex_, NULL); if (status != 0) { LOG4CXX_ERROR(logger_, "Failed to initialize mutex"); } @@ -55,8 +57,8 @@ Lock::Lock() Lock::Lock(bool is_mutex_recursive) #ifndef NDEBUG - : lock_taken_(0), - is_mutex_recursive_(is_mutex_recursive) + : lock_taken_(0), + is_mutex_recursive_(is_mutex_recursive) #endif // NDEBUG { int32_t status; @@ -67,6 +69,7 @@ Lock::Lock(bool is_mutex_recursive) pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); status = pthread_mutex_init(&mutex_, &attr); + pthread_mutexattr_destroy(&attr); } else { status = pthread_mutex_init(&mutex_, NULL); } @@ -79,54 +82,41 @@ Lock::Lock(bool is_mutex_recursive) Lock::~Lock() { #ifndef NDEBUG if (lock_taken_ > 0) { - LOG4CXX_ERROR(logger_, "Destroying non-released mutex"); + LOG4CXX_ERROR(logger_, "Destroying non-released mutex " << &mutex_); } #endif int32_t status = pthread_mutex_destroy(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to destroy mutex"); + LOG4CXX_ERROR(logger_, "Failed to destroy mutex " << &mutex_ << ": " << strerror(status)); } } void Lock::Acquire() { - int32_t status = pthread_mutex_lock(&mutex_); + const int32_t status = pthread_mutex_lock(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to acquire mutex"); + LOG4CXX_ERROR(logger_, "Failed to acquire mutex " << &mutex_ << ": " << strerror(status)); + } else { + AssertFreeAndMarkTaken(); } - AssertFreeAndMarkTaken(); } void Lock::Release() { AssertTakenAndMarkFree(); - int32_t status = pthread_mutex_unlock(&mutex_); + const int32_t status = pthread_mutex_unlock(&mutex_); if (status != 0) { - LOG4CXX_ERROR(logger_, "Failed to unlock mutex"); + LOG4CXX_ERROR(logger_, "Failed to unlock mutex" << &mutex_ << ": " << strerror(status)); } } bool Lock::Try() { - bool ackquired = false; -#ifndef NDEBUG - if ((lock_taken_ > 0) && !is_mutex_recursive_) { - LOG4CXX_ERROR(logger_, "Trying to lock already taken not recurcive mutex"); - } -#endif - switch(pthread_mutex_trylock(&mutex_)) { - case 0: { - ackquired = true; + const int32_t status = pthread_mutex_trylock(&mutex_); + if (status == 0) { #ifndef NDEBUG - lock_taken_++; + lock_taken_++; #endif - } break; - case EBUSY: { - ackquired = false; - } break; - default: { - ackquired = false; - LOG4CXX_ERROR(logger_, "Failed to try lock the mutex"); - } + return true; } - return ackquired; + return false; } #ifndef NDEBUG @@ -146,5 +136,4 @@ void Lock::AssertTakenAndMarkFree() { } #endif - -} // namespace sync_primitives +} // namespace sync_primitives diff --git a/src/components/utils/src/logger_status.cc b/src/components/utils/src/logger_status.cc index be341b9add..ea9dfa3f22 100644 --- a/src/components/utils/src/logger_status.cc +++ b/src/components/utils/src/logger_status.cc @@ -34,6 +34,6 @@ namespace logger { -LoggerStatus logger_status = LoggerThreadNotCreated; +volatile LoggerStatus logger_status = LoggerThreadNotCreated; } // namespace logger diff --git a/src/components/utils/src/resource_usage.cc b/src/components/utils/src/resource_usage.cc index aaa9c1b4a7..62c8d25b82 100644 --- a/src/components/utils/src/resource_usage.cc +++ b/src/components/utils/src/resource_usage.cc @@ -124,6 +124,8 @@ bool Resources::GetProcInfo(Resources::PidStats& output) { if (0 >= fd) { LOG4CXX_ERROR(logger_, "Failed open process proc file : " << GetProcPath() << "; error no : " << strerror( errno ) ); + + close(fd); return false; } devctl(fd, DCMD_PROC_INFO, &output, sizeof(output), 0); @@ -148,14 +150,14 @@ bool Resources::GetMemInfo(Resources::MemInfo &output) { std::string as_path = GetStatPath(); struct stat st; struct _dir* proc_dir = 0; - struct dirent* proc_entry = 0; if (0 == (proc_dir = opendir(proc))) { LOG4CXX_ERROR(logger_, "Unable to access to " << proc); result = false; return result; } - if (0 == (proc_entry = readdir(proc_dir))) { + if (0 == readdir(proc_dir)) { LOG4CXX_ERROR(logger_, "Unable to read : " << proc_dir); + closedir(proc_dir); result = false; return result; } diff --git a/src/components/utils/src/rwlock_posix.cc b/src/components/utils/src/rwlock_posix.cc index 7cc850b25b..08edb8cb0c 100644 --- a/src/components/utils/src/rwlock_posix.cc +++ b/src/components/utils/src/rwlock_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,22 +49,44 @@ RWLock::~RWLock() { } } -void RWLock::AcquireForReading() { +bool RWLock::AcquireForReading() { if (pthread_rwlock_rdlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for reading"); + return false; } + return true; } -void RWLock::AcquireForWriting() { +bool RWLock::TryAcquireForReading() { + if (pthread_rwlock_tryrdlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for reading"); + return false; + } + return true; +} + +bool RWLock::AcquireForWriting() { if (pthread_rwlock_wrlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for writing"); + return false; + } + return true; +} + +bool RWLock::TryAcquireForWriting() { + if (pthread_rwlock_trywrlock(&rwlock_) != 0) { + LOG4CXX_ERROR(logger_, "Failed to acquire rwlock for writing"); + return false; } + return true; } -void RWLock::Release() { +bool RWLock::Release() { if (pthread_rwlock_unlock(&rwlock_) != 0) { LOG4CXX_ERROR(logger_, "Failed to release rwlock"); + return false; } + return true; } } // namespace sync_primitives diff --git a/src/components/utils/src/signals_linux.cc b/src/components/utils/src/signals_linux.cc index 3ded6a5877..2e598d1b0f 100644 --- a/src/components/utils/src/signals_linux.cc +++ b/src/components/utils/src/signals_linux.cc @@ -1,54 +1,63 @@ /* -* Copyright (c) 2014, Ford Motor Company -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following -* disclaimer in the documentation and/or other materials provided with the -* distribution. -* -* Neither the name of the Ford Motor Company nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #include <csignal> #include <cstdlib> #include <stdint.h> +#include "utils/signals.h" + namespace utils { -bool SubscribeToTerminateSignal(void (*func)(int32_t p)) { +bool SubscribeToTerminateSignal(sighandler_t func) { struct sigaction act; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; - return (sigaction(SIGINT, &act, NULL) == 0) - && (sigaction(SIGTERM, &act, NULL) == 0); + bool sigint_subscribed = (sigaction(SIGINT, &act, NULL) == 0); + bool sigterm_subscribed = (sigaction(SIGTERM, &act, NULL) == 0); + + return sigint_subscribed && sigterm_subscribed; } -bool ResetSubscribeToTerminateSignal() { - void (*prev_func)(int32_t p); - prev_func = signal(SIGINT, SIG_DFL); - return (SIG_ERR != prev_func); +bool SubscribeToFaultSignal(sighandler_t func) { + struct sigaction act; + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESETHAND; // we only want to catch SIGSEGV once to flush logger queue + + bool sigsegv_subscribed = (sigaction(SIGSEGV, &act, NULL) == 0); + + return sigsegv_subscribed; } } // namespace utils diff --git a/src/components/utils/src/system.cc b/src/components/utils/src/system.cc index ee90315db0..70659419a7 100644 --- a/src/components/utils/src/system.cc +++ b/src/components/utils/src/system.cc @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2014, Ford Motor Company * All rights reserved. * @@ -42,6 +42,7 @@ #include <algorithm> #include <functional> #include <cstring> +#include <iostream> #include "utils/logger.h" #include "utils/system.h" @@ -66,15 +67,23 @@ System::System(const std::string& file, const std::string& command) argv_.push_back(command); } -bool System::Execute() { - return Execute(false); -} - System& System::Add(const std::string& arg) { argv_.push_back(arg); return *this; } +std::string System::command() const { + return command_; +} + +std::vector<std::string> System::argv() const { + return argv_; +} + +bool System::Execute() { + return Execute(false); +} + #ifdef __QNX__ bool System::Execute(bool wait) { @@ -89,7 +98,7 @@ bool System::Execute(bool wait) { if (ret == -1) { LOG4CXX_ERROR(logger_, "Can't execute command: " << command_ - << " Errno is: " << std::strerror(errno)); + << " Errno is: " << std::strerror(errno)); return false; } diff --git a/src/components/utils/src/threads/posix_thread.cc b/src/components/utils/src/threads/posix_thread.cc index 3f7e006eca..82dd8c59b3 100644 --- a/src/components/utils/src/threads/posix_thread.cc +++ b/src/components/utils/src/threads/posix_thread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,125 +31,168 @@ */ #include <errno.h> - #include <limits.h> #include <stddef.h> #include <signal.h> -#include "utils/atomic.h" +#ifdef BUILD_TESTS +// Temporary fix for UnitTest until APPLINK-9987 is resolved +#include <unistd.h> +#endif + #include "utils/threads/thread.h" -#include "utils/threads/thread_manager.h" -#include "utils/logger.h" #include "pthread.h" - +#include "utils/atomic.h" +#include "utils/threads/thread_delegate.h" +#include "utils/logger.h" #ifndef __QNXNTO__ - const int EOK = 0; +const int EOK = 0; #endif #if defined(OS_POSIX) - const size_t THREAD_NAME_SIZE = 15; +const size_t THREAD_NAME_SIZE = 15; #endif namespace threads { CREATE_LOGGERPTR_GLOBAL(logger_, "Utils") -namespace { - -static void* threadFunc(void* arg) { - LOG4CXX_INFO(logger_, "Thread #" << pthread_self() << " started successfully"); - threads::Thread* thread = static_cast<threads::Thread*>(arg); - threads::ThreadDelegate* delegate = thread->delegate(); - delegate->threadMain(); - thread->set_running(false); - MessageQueue<ThreadManager::ThreadDesc>& threads = ::threads::ThreadManager::instance()->threads_to_terminate; - if (!threads.IsShuttingDown()) { - LOG4CXX_INFO(logger_, "Pushing thread #" << pthread_self() << " to join queue"); - ThreadManager::ThreadDesc desc = { pthread_self(), delegate }; - threads.push(desc); - } - LOG4CXX_INFO(logger_, "Thread #" << pthread_self() << " exited successfully"); - return NULL; -} +size_t Thread::kMinStackSize = PTHREAD_STACK_MIN; /* Ubuntu : 16384 ; QNX : 256; */ +void Thread::cleanup(void* arg) { + LOG4CXX_AUTO_TRACE(logger_); + Thread* thread = reinterpret_cast<Thread*>(arg); + sync_primitives::AutoLock auto_lock(thread->state_lock_); + thread->isThreadRunning_ = false; + thread->state_cond_.Broadcast(); } -size_t Thread::kMinStackSize = PTHREAD_STACK_MIN; /* Ubuntu : 16384 ; QNX : 256; */ +void* Thread::threadFunc(void* arg) { + // 0 - state_lock unlocked + // stopped = 0 + // running = 0 + // finalized = 0 + // 4 - state_lock unlocked + // stopped = 1 + // running = 1 + // finalized = 0 + // 5 - state_lock unlocked + // stopped = 1 + // running = 1 + // finalized = 1 + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + LOG4CXX_DEBUG(logger_, + "Thread #" << pthread_self() << " started successfully"); + + threads::Thread* thread = reinterpret_cast<Thread*>(arg); + DCHECK(thread); + + pthread_cleanup_push(&cleanup, thread); + + thread->state_lock_.Acquire(); + thread->state_cond_.Broadcast(); + + while (!thread->finalized_) { + LOG4CXX_DEBUG(logger_, "Thread #" << pthread_self() << " iteration"); + thread->run_cond_.Wait(thread->state_lock_); + LOG4CXX_DEBUG( + logger_, + "Thread #" << pthread_self() << " execute. " << "stopped_ = " << thread->stopped_ << "; finalized_ = " << thread->finalized_); + if (!thread->stopped_ && !thread->finalized_) { + thread->isThreadRunning_ = true; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + + thread->state_lock_.Release(); + thread->delegate_->threadMain(); + thread->state_lock_.Acquire(); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + thread->isThreadRunning_ = false; + } + thread->state_cond_.Broadcast(); + LOG4CXX_DEBUG(logger_, + "Thread #" << pthread_self() << " finished iteration"); + } -/* -void ThreadBase::set_name(const std::string name) { - std::string trimname = name.erase(15); - if(pthread_setname_np(thread_handle_, trimname.c_str()) != EOK) { - LOG4CXX_WARN(logger_, "Couldn't set pthread name \"" - << trimname - << "\", error code " - << pthread_result - << " (" - << strerror(pthread_result) - << ")"); - } + thread->state_lock_.Release(); + pthread_cleanup_pop(1); + + LOG4CXX_DEBUG(logger_, + "Thread #" << pthread_self() << " exited successfully"); + return NULL; } -*/ - -void Thread::SetNameForId(const Id& thread_id, const std::string& name) { - std::string nm = name; - std::string& trimname = nm.size() > 15 ? nm.erase(15) : nm; - const int rc = pthread_setname_np(thread_id.id_, trimname.c_str()); - if(rc == EOK) { - LOG4CXX_WARN(logger_, "Couldn't set pthread name \"" - << trimname - << "\", error code " - << rc - << " (" - << strerror(rc) - << ")"); + +void Thread::SetNameForId(const PlatformThreadHandle& thread_id, + std::string name) { + if (name.size() > THREAD_NAME_SIZE) + name.erase(THREAD_NAME_SIZE); + const int rc = pthread_setname_np(thread_id, name.c_str()); + if (rc != EOK) { + LOG4CXX_WARN( + logger_, + "Couldn't set pthread name \"" << name << "\", error code " << rc << " (" << strerror(rc) << ")"); } } Thread::Thread(const char* name, ThreadDelegate* delegate) - : name_(name ? name : "undefined"), - delegate_(delegate), - thread_handle_(0), - thread_options_(), - isThreadRunning_(0) { -} - -ThreadDelegate* Thread::delegate() const { - return delegate_; + : name_(name ? name : "undefined"), + delegate_(delegate), + handle_(0), + thread_options_(), + isThreadRunning_(0), + stopped_(false), + finalized_(false), + thread_created_(false) { } bool Thread::start() { - return startWithOptions(thread_options_); + return start(thread_options_); } -Thread::Id Thread::CurrentId() { - return Id(pthread_self()); +PlatformThreadHandle Thread::CurrentId() { + return pthread_self(); } -bool Thread::startWithOptions(const ThreadOptions& options) { - LOG4CXX_TRACE_ENTER(logger_); +bool Thread::start(const ThreadOptions& options) { + LOG4CXX_AUTO_TRACE(logger_); + + sync_primitives::AutoLock auto_lock(state_lock_); + // 1 - state_lock locked + // stopped = 0 + // running = 0 + if (!delegate_) { - NOTREACHED(); - LOG4CXX_ERROR(logger_, "NULL delegate"); - LOG4CXX_TRACE_EXIT(logger_); + LOG4CXX_ERROR(logger_, + "Cannot start thread " << name_ << ": delegate is NULL"); + // 0 - state_lock unlocked return false; } + if (isThreadRunning_) { + LOG4CXX_TRACE( + logger_, + "EXIT thread "<< name_ << " #" << handle_ << " is already running"); + return true; + } + thread_options_ = options; pthread_attr_t attributes; int pthread_result = pthread_attr_init(&attributes); if (pthread_result != EOK) { - LOG4CXX_WARN(logger_,"Couldn't init pthread attributes. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); + LOG4CXX_WARN( + logger_, + "Couldn't init pthread attributes. Error code = " << pthread_result << " (\"" << strerror(pthread_result) << "\")"); } if (!thread_options_.is_joinable()) { pthread_result = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); if (pthread_result != EOK) { - LOG4CXX_WARN(logger_,"Couldn't set detach state attribute.. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); + LOG4CXX_WARN( + logger_, + "Couldn't set detach state attribute. Error code = " << pthread_result << " (\"" << strerror(pthread_result) << "\")"); thread_options_.is_joinable(false); } } @@ -158,72 +201,94 @@ bool Thread::startWithOptions(const ThreadOptions& options) { if (stack_size >= Thread::kMinStackSize) { pthread_result = pthread_attr_setstacksize(&attributes, stack_size); if (pthread_result != EOK) { - LOG4CXX_WARN(logger_,"Couldn't set stacksize = " << stack_size << - ". Error code = " << pthread_result << "(\"" - << strerror(pthread_result) << "\")"); + LOG4CXX_WARN( + logger_, + "Couldn't set stacksize = " << stack_size << ". Error code = " << pthread_result << " (\"" << strerror(pthread_result) << "\")"); } } + else { + ThreadOptions thread_options_temp(Thread::kMinStackSize, thread_options_.is_joinable()); + thread_options_ = thread_options_temp; + } - pthread_result = pthread_create(&thread_handle_, &attributes, threadFunc, this); - isThreadRunning_ = (pthread_result == EOK); - if (!isThreadRunning_) { - LOG4CXX_WARN(logger_, "Couldn't create thread. Error code = " - << pthread_result << "(\"" << strerror(pthread_result) << "\")"); - } else { - LOG4CXX_INFO(logger_,"Created thread: " << name_); - SetNameForId(Id(thread_handle_), name_); + if (!thread_created_) { + // state_lock 1 + pthread_result = pthread_create(&handle_, &attributes, threadFunc, this); + if (pthread_result == EOK) { + LOG4CXX_DEBUG(logger_, "Created thread: " << name_); + SetNameForId(handle_, name_); + // state_lock 0 + // possible concurrencies: stop and threadFunc + state_cond_.Wait(auto_lock); + thread_created_ = true; + } else { + LOG4CXX_ERROR( + logger_, + "Couldn't create thread " << name_ << ". Error code = " << pthread_result << " (\"" << strerror(pthread_result) << "\")"); + } } - LOG4CXX_TRACE_EXIT(logger_); - return isThreadRunning_; + stopped_ = false; + run_cond_.NotifyOne(); + LOG4CXX_DEBUG( + logger_, + "Thread " << name_ << " #" << handle_ << " started. pthread_result = " << pthread_result); + pthread_attr_destroy(&attributes); + return pthread_result == EOK; } void Thread::stop() { - LOG4CXX_TRACE_ENTER(logger_); + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock auto_lock(state_lock_); - if (!atomic_post_clr(&isThreadRunning_)) - { - return; - } +#ifdef BUILD_TESTS + // Temporary fix for UnitTest until APPLINK-9987 is resolved + usleep(100000); +#endif - if (delegate_ && !delegate_->exitThreadMain()) { - if (thread_handle_ != pthread_self()) { - LOG4CXX_WARN(logger_, "Cancelling thread #" << thread_handle_); - const int pthread_result = pthread_cancel(thread_handle_); - if (pthread_result != EOK) { - LOG4CXX_WARN(logger_, - "Couldn't cancel thread (#" << thread_handle_ << " \"" << name_ << - "\") from thread #" << pthread_self() << ". Error code = " - << pthread_result << " (\"" << strerror(pthread_result) << "\")"); - } - } else { - LOG4CXX_ERROR(logger_, - "Couldn't cancel the same thread (#" << thread_handle_ - << "\"" << name_ << "\")"); - } + stopped_ = true; + + LOG4CXX_DEBUG(logger_, "Stopping thread #" << handle_ + + << " \"" << name_ << " \""); + + if (delegate_ && isThreadRunning_) { + delegate_->exitThreadMain(); } - LOG4CXX_TRACE_EXIT(logger_); + LOG4CXX_DEBUG(logger_, + "Stopped thread #" << handle_ << " \"" << name_ << " \""); } -bool Thread::Id::operator==(const Thread::Id& other) const { - return pthread_equal(id_, other.id_) != 0; -} +void Thread::join() { + LOG4CXX_AUTO_TRACE(logger_); + DCHECK(!pthread_equal(pthread_self(), handle_)); -std::ostream& operator<<(std::ostream& os, const Thread::Id& thread_id) { - char name[32]; - if(pthread_getname_np(thread_id.Handle(), name, 32) == 0) { - os << name; + stop(); + + sync_primitives::AutoLock auto_lock(state_lock_); + run_cond_.NotifyOne(); + if (isThreadRunning_) { + if (!pthread_equal(pthread_self(), handle_)) { + state_cond_.Wait(auto_lock); + } } - return os; +} + +Thread::~Thread() { + finalized_ = true; + stopped_ = true; + join(); + pthread_join(handle_, NULL); } Thread* CreateThread(const char* name, ThreadDelegate* delegate) { - return new Thread(name, delegate); + Thread* thread = new Thread(name, delegate); + delegate->set_thread(thread); + return thread; } void DeleteThread(Thread* thread) { delete thread; } - } // namespace threads diff --git a/src/components/utils/src/threads/pulse_thread_delegate.cc b/src/components/utils/src/threads/pulse_thread_delegate.cc index 8c580bea83..68db5dcbea 100644 --- a/src/components/utils/src/threads/pulse_thread_delegate.cc +++ b/src/components/utils/src/threads/pulse_thread_delegate.cc @@ -91,7 +91,7 @@ void PulseThreadDelegate::threadMain() { Finalize(); } -bool PulseThreadDelegate::exitThreadMain() { +void PulseThreadDelegate::exitThreadMain() { run_ = false; LOG4CXX_TRACE(logger_, "Disconnecting from QNX channel " << chid_); @@ -109,8 +109,6 @@ bool PulseThreadDelegate::exitThreadMain() { else { LOG4CXX_WARN(logger_, "Failed to destroy QNX channel " << chid_); } - - return true; } } // namespace threads diff --git a/src/components/utils/src/threads/thread_delegate.cc b/src/components/utils/src/threads/thread_delegate.cc index 13271166ff..1436ea3377 100644 --- a/src/components/utils/src/threads/thread_delegate.cc +++ b/src/components/utils/src/threads/thread_delegate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,7 @@ namespace threads { ThreadDelegate::~ThreadDelegate() { - if(thread_) { + if (thread_) { thread_->set_delegate(NULL); } } @@ -60,4 +60,4 @@ void ThreadDelegate::set_thread(Thread *thread) { thread_ = thread; } -} +} // namespace threads diff --git a/src/components/utils/src/threads/thread_validator.cc b/src/components/utils/src/threads/thread_validator.cc index 5e9c88a7c9..99b812c456 100644 --- a/src/components/utils/src/threads/thread_validator.cc +++ b/src/components/utils/src/threads/thread_validator.cc @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2013, Ford Motor Company +/* + * Copyright (c) 2014, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ SingleThreadSimpleValidator::~SingleThreadSimpleValidator() { } void SingleThreadSimpleValidator::AssertRunningOnCreationThread() const { - Thread::Id current_id = Thread::CurrentId(); + PlatformThreadHandle current_id = Thread::CurrentId(); if (creation_thread_id_ != current_id) { LOG4CXX_ERROR(logger_, "Single-threaded object created at thread " << creation_thread_id_ @@ -60,6 +60,11 @@ void SingleThreadSimpleValidator::AssertRunningOnCreationThread() const { } } +PlatformThreadHandle SingleThreadSimpleValidator::creation_thread_id() const +{ + return creation_thread_id_; +} + SingleThreadValidator::SingleThreadValidator() : owning_thread_id_(Thread::CurrentId()){ @@ -68,12 +73,12 @@ SingleThreadValidator::SingleThreadValidator() SingleThreadValidator::~SingleThreadValidator() { } -void SingleThreadValidator::PassToThread(Thread::Id thread_id) const { +void SingleThreadValidator::PassToThread(PlatformThreadHandle thread_id) const { owning_thread_id_ = thread_id; } void SingleThreadValidator::AssertRunningOnValidThread() const { - Thread::Id current_id = Thread::CurrentId(); + PlatformThreadHandle current_id = Thread::CurrentId(); if (owning_thread_id_ != current_id) { LOG4CXX_ERROR(logger_, "Single-threaded object owned by thread " << owning_thread_id_ diff --git a/src/components/utils/test/CMakeLists.txt b/src/components/utils/test/CMakeLists.txt index a9ed5acdac..377b7dba7b 100644 --- a/src/components/utils/test/CMakeLists.txt +++ b/src/components/utils/test/CMakeLists.txt @@ -1,17 +1,80 @@ +# Copyright (c) 2015, Ford Motor Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of the Ford Motor Company nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +if(BUILD_TESTS) + include_directories ( ${CMAKE_SOURCE_DIR}/src/3rd_party-static/gmock-1.7.0/include - ${CMAKE_SOURCE_DIR}/src/3rd_party-static/gmock-1.7.0/gtest/include) + ${CMAKE_SOURCE_DIR}/src/3rd_party-static/gmock-1.7.0/gtest/include + ${COMPONENTS_DIR}/include/utils + ) set(testSources main.cc + messagemeter_test.cc file_system_test.cc - date_time_test.cc) + date_time_test.cc + system_test.cc + signals_linux_test.cc + thread_validator_test.cc + conditional_variable_test.cc + message_queue_test.cc + resource_usage_test.cc + bitstream_test.cc + data_accessor_test.cc + lock_posix_test.cc + singleton_test.cc + #posix_thread_test.cc + stl_utils_test.cc + timer_thread_test.cc + rwlock_posix_test.cc + async_runner_test.cc +) + +if (ENABLE_LOG) + list(APPEND testSources auto_trace_test.cc) + list(APPEND testSources log_message_loop_thread_test.cc) +endif() + +if (BUILD_BACKTRACE_SUPPORT) + list(APPEND testSources back_trace_test.cc) +endif() set(testLibraries gmock - gtest - Utils) + Utils +) + +file(COPY testscript.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY log4cxx.properties DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -add_executable(utils_test ${testSources}) -target_link_libraries(utils_test ${testLibraries}) +create_test("utils_test" "${testSources}" "${testLibraries}") +endif() diff --git a/src/components/utils/test/async_runner_test.cc b/src/components/utils/test/async_runner_test.cc new file mode 100644 index 0000000000..38606c15ac --- /dev/null +++ b/src/components/utils/test/async_runner_test.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <ctime> +#include "lock.h" +#include "threads/async_runner.h" +#include "utils/conditional_variable.h" + +#include "gtest/gtest.h" + +namespace test { +namespace components { +namespace utils { + +using namespace sync_primitives; +using namespace threads; + +namespace { +uint32_t check_value = 0; +} + +// ThreadDelegate successor +class TestThreadDelegate : public ThreadDelegate { + public: + void threadMain() { + ++check_value; + } +}; + +class AsyncRunnerTest : public ::testing::Test { + public: + AsyncRunnerTest() + : kDelegatesNum_(1), + asr_pt_(NULL) { + CreateAsyncRunner(); + CreateThreadsArray(); + } + + ~AsyncRunnerTest() { + DeleteAsyncRunner(); + DeleteThreadsArray(); + } + + protected: + Lock test_lock_; + uint32_t kDelegatesNum_; + ConditionalVariable cond_var_; + TestThreadDelegate **delegates_; + AsyncRunner *asr_pt_; + + void CreateThreadsArray() { + srand(std::time(NULL)); + kDelegatesNum_ = (rand() % 20 + 1); + delegates_ = new TestThreadDelegate*[kDelegatesNum_]; + } + + void DeleteThreadsArray() { + delete[] delegates_; + } + + void CreateAsyncRunner() { + asr_pt_ = new AsyncRunner("test"); + } + void DeleteAsyncRunner() { + delete asr_pt_; + } +}; + +TEST_F(AsyncRunnerTest, ASyncRunManyDelegates_ExpectSuccessfulAllDelegatesRun) { + AutoLock lock(test_lock_); + // Clear global value before test + check_value = 0; + // Create Delegates and run + for (unsigned int i = 0; i < kDelegatesNum_; ++i) { + delegates_[i] = new TestThreadDelegate(); + asr_pt_->AsyncRun(delegates_[i]); + } + // Wait for 2 secs. Give this time to delegates to be run + cond_var_.WaitFor(lock, 2000); + // Expect all delegates run successfully + EXPECT_EQ(kDelegatesNum_, check_value); +} + +TEST_F(AsyncRunnerTest, RunManyDelegatesAndStop_ExpectSuccessfulDelegatesStop) { + AutoLock lock(test_lock_); + // Clear global value before test + check_value = 0; + // Create Delegates + for (unsigned int i = 0; i < kDelegatesNum_; ++i) { + delegates_[i] = new TestThreadDelegate(); + } + // Wait for 2 secs + cond_var_.WaitFor(lock, 2000); + // Run created delegates + for (unsigned int i = 0; i < kDelegatesNum_; ++i) { + if (kDelegatesNum_ > 1) { + if (i == kDelegatesNum_ / 2) { + asr_pt_->Stop(); + } + } + asr_pt_->AsyncRun(delegates_[i]); + } + // Expect 3 delegates run successlully. The other stopped. + EXPECT_EQ(kDelegatesNum_ / 2, check_value); +} + +} // namespace utils +} // namespace components +} // namespace test + diff --git a/src/components/utils/test/auto_trace_test.cc b/src/components/utils/test/auto_trace_test.cc new file mode 100644 index 0000000000..71e0f4376f --- /dev/null +++ b/src/components/utils/test/auto_trace_test.cc @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/auto_trace.h" +#include "logger.h" +#include <fstream> + +namespace test { +namespace components { +namespace utils { + +using namespace ::logger; + +CREATE_LOGGERPTR_GLOBAL(logger_, "AutoTraceTestLog"); + +void Preconditions() { + //delete file with previous logs + const char* file_name = "AutoTraceTestLogFile.log"; + std::remove(file_name); +} + +void InitLogger() { + INIT_LOGGER("log4cxx.properties"); +} + +void CreateDeleteAutoTrace(const std::string & testlog) { + LOG4CXX_AUTO_TRACE(logger_); + LOG4CXX_DEBUG(logger_, testlog); +} + +bool CheckTraceInFile(const std::string & testlog) { + + bool isLogFound = false; + std::string line; + + std::ifstream file_log("AutoTraceTestLogFile.log"); + + if (file_log.is_open()) { + while (getline(file_log, line)) { + std::size_t found = line.find(testlog); + std::size_t founddebug = line.find("DEBUG"); + if ((found != std::string::npos) && (founddebug != std::string::npos)) { + isLogFound = true; + break; + } + } + file_log.close(); + } else { + std::cout << "file cannot be opened \n"; + } + return isLogFound; +} + +void DeinitLogger() { + DEINIT_LOGGER(); +} + +TEST(AutoTraceTest, Basic) { + const std::string testlog = + "Test trace is working!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + Preconditions(); + InitLogger(); + CreateDeleteAutoTrace(testlog); + DeinitLogger(); + + ASSERT_TRUE(CheckTraceInFile(testlog)); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/back_trace_test.cc b/src/components/utils/test/back_trace_test.cc new file mode 100644 index 0000000000..12d5df81fc --- /dev/null +++ b/src/components/utils/test/back_trace_test.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/back_trace.h" + +namespace test { +namespace components { +namespace utils { + +using namespace ::utils; + +TEST(BackTraceTest, CallStackShouldNotBeEmpty) { + + //arrange + Backtrace newtrace = Backtrace(); + std::vector < std::string > symbols = newtrace.CallStack(); + //assert + ASSERT_FALSE(symbols.empty()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/bitstream_test.cc b/src/components/utils/test/bitstream_test.cc new file mode 100644 index 0000000000..07a80bde07 --- /dev/null +++ b/src/components/utils/test/bitstream_test.cc @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include "gtest/gtest.h" +#include "utils/macro.h" +#include "utils/bitstream.h" + +namespace test { +namespace components { +namespace utils { + +using ::utils::BitStream; + +TEST(BitstreamTest, CreateBitstream_WithDataWithDatasize_BitStreamIsGood) { + + //arrange + uint8_t data = 10; + size_t bits = 2; + BitStream bs(&data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, ExtractBitstreamInUint8_ExtractAllData_BitStreamIsGoodDataExtractedCorrectly) { + + //arrange + uint8_t data = 10; + size_t bits = 2; + BitStream bs(&data, bits); + + uint8_t extract_data = 0; + Extract(&bs, &extract_data); + + //assert + EXPECT_TRUE(bs.IsGood()); + + EXPECT_EQ(data, extract_data); +} + +TEST(BitstreamTest, ExtractBitstreamInUint8_WithDataWithZeroSize_BitStreamIsBad) { + + //arrange + uint8_t data = 10; + size_t bits = 0; + BitStream bs(&data, bits); + + uint8_t extract_data = 0; + Extract(&bs, &extract_data); + + //assert + EXPECT_TRUE(bs.IsBad()); +} + +TEST(BitstreamTest, ExtractBitstreamInUint32_WithDatasizeEq4_BitStreamIsGoodDataExtractedCorrectly) { + + //arrange + uint8_t data = 10; + size_t bits = 4; + BitStream bs(&data, bits); + + uint32_t extract_data = 0; + Extract(&bs, &extract_data); + + //assert + EXPECT_TRUE(bs.IsGood()); + +} + +TEST(BitstreamTest, ExtractBitstreamInUint32_DatasizeLess4_BitStreamIsBad) { + + //arrange + uint8_t data = 10; + size_t bits = 3; + BitStream bs(&data, bits); + + uint32_t extract_data = 0; + Extract(&bs, &extract_data); + + //assert + EXPECT_TRUE(bs.IsBad()); + +} + +TEST(BitstreamTest, ExtractFullBitstream_WithDataWithDatasize_BitStreamIsGood) { + + //arrange + uint8_t data = 10; + size_t bits = 8; + BitStream bs(&data, bits); + + uint8_t extract_data = 0; + + Extract(&bs, &extract_data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); + + EXPECT_EQ(data, extract_data); +} + +TEST(BitstreamTest, ExtractBitstreamInString_WithDataWithDatasize_BitStreamIsGood) { + + //arrange + uint8_t data = 10; + size_t bits = 2; + BitStream bs(&data, bits); + + std::string strdata = ""; + size_t length = strdata.length(); + + Extract(&bs, &strdata, length); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, CreateBitstream_NoDataZeroDatasize_BitStreamIsGood) { + + //arrange + uint8_t *data = NULL; + size_t bits = 0; + BitStream bs(data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, CreateBitstream_NoDataWithUpperboundDataSize_BitStreamIsGood) { + + //arrange + uint8_t *data = NULL; + size_t bits = 65535; + BitStream bs(data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, CreateBitstream_WithUpperboundDataWithLessDataSize_BitStreamIsGood) { + + //arrange + uint8_t data = 255; + size_t bits = sizeof(char); + BitStream bs(&data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, ExtractBitstream_WithUpperboundDataWithLessDataSize_BitStreamIsGood) { + + //arrange + uint8_t data = 255; + size_t bits = sizeof(char); + BitStream bs(&data, bits); + + uint8_t extract_data = 0; + Extract(&bs, &extract_data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, ExtractBitstream_WithUpperboundDataWithZeroDataSize_BitStreamIsGood) { + + //arrange + uint8_t data = 255; + size_t bits = 0; + BitStream bs(&data, bits); + + uint8_t extract_data = 0; + Extract(&bs, &extract_data, bits); + + //assert + EXPECT_TRUE(bs.IsGood()); +} + +TEST(BitstreamTest, ExtractBitstream_WithDataMarkedBad_ExpectIsBad) { + + //arrange + uint8_t data = 255; + size_t bits = sizeof(int); + BitStream bs(&data, bits); + //assert + EXPECT_TRUE(bs.IsGood()); + //act + bs.MarkBad(); + + //assert + EXPECT_TRUE(bs.IsBad()); + //act + Extract(&bs, &data, bits); + //arrange + EXPECT_TRUE(bs.IsBad()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/conditional_variable_test.cc b/src/components/utils/test/conditional_variable_test.cc new file mode 100644 index 0000000000..a898732ffc --- /dev/null +++ b/src/components/utils/test/conditional_variable_test.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <pthread.h> +#include <iostream> + +#include "lock.h" +#include "macro.h" + +#include "gtest/gtest.h" +#include "utils/conditional_variable.h" + +namespace test { +namespace components { +namespace utils { + +class ConditionalVariableTest : public ::testing::Test { + public: + ConditionalVariableTest() + : test_value_("initialized"), + counter_(0) { + } + void check_counter(); + void task_one(); + + static void* check_counter_helper(void *context) { + (reinterpret_cast<ConditionalVariableTest *>(context))->check_counter(); + return NULL; + } + + static void* task_one_helper(void *context) { + (reinterpret_cast<ConditionalVariableTest *>(context))->task_one(); + return NULL; + } + protected: + std::string test_value_; + sync_primitives::ConditionalVariable cond_var_; + sync_primitives::Lock test_mutex_; + unsigned counter_; +}; + +// Defines threads behaviour which depends on counter value +void ConditionalVariableTest::check_counter() { + sync_primitives::AutoLock test_lock(test_mutex_); + if (counter_ <= 1) { + counter_++; + cond_var_.Wait(test_mutex_); // Mutex unlock & Thread sleeps until Notification + } + else if(counter_ == 2) { // Checking for equal 2 in this specific case. Because we were waiting for 2 threads to be finished + cond_var_.Broadcast(); // Notify All threads waiting on conditional variable + } +} + +// Tasks for threads to begin with +void ConditionalVariableTest::task_one() { + sync_primitives::AutoLock test_lock(test_mutex_); + test_value_ = "changed by thread 1"; + cond_var_.NotifyOne(); // Notify At least one thread waiting on conditional variable + test_value_ = "changed again by thread 1"; +} + +TEST_F(ConditionalVariableTest, CheckNotifyOne_OneThreadNotified_ExpectSuccessful) { + pthread_t thread1; + sync_primitives::AutoLock test_lock(test_mutex_); + test_value_ = "changed by main thread"; + const bool thread_created = pthread_create(&thread1, + NULL, + &ConditionalVariableTest::task_one_helper, + this); + ASSERT_FALSE(thread_created) << "thread1 is not created!"; + test_value_ = "changed twice by main thread"; + cond_var_.WaitFor(test_lock, 2000); + std::string last_value("changed again by thread 1"); + EXPECT_EQ(last_value, test_value_); +} + +TEST_F(ConditionalVariableTest, CheckBroadcast_AllThreadsNotified_ExpectSuccessful) { + pthread_t thread1; + pthread_t thread2; + bool thread_created = pthread_create(&thread1, + NULL, + &ConditionalVariableTest::check_counter_helper, + this); + ASSERT_FALSE(thread_created) << "thread1 is not created!"; + thread_created = pthread_create(&thread2, + NULL, + &ConditionalVariableTest::check_counter_helper, + this); + ASSERT_FALSE(thread_created) << "thread2 is not created!"; + check_counter(); + EXPECT_EQ(2u, counter_); +} + +TEST_F(ConditionalVariableTest, CheckWaitForWithTimeout1sec_ThreadBlockedForTimeout_ExpectSuccessfulWakeUp) { + sync_primitives::AutoLock test_lock(test_mutex_); + sync_primitives::ConditionalVariable::WaitStatus wait_st = cond_var_.WaitFor(test_lock, 1000); + EXPECT_EQ(sync_primitives::ConditionalVariable::kTimeout, wait_st); +} + +} // namespace utils +} // namespace components +} // namespace test + diff --git a/src/components/utils/test/data_accessor_test.cc b/src/components/utils/test/data_accessor_test.cc new file mode 100644 index 0000000000..105ec8517f --- /dev/null +++ b/src/components/utils/test/data_accessor_test.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/data_accessor.h" +#include "utils/lock.h" + +namespace test { +namespace components { +namespace utils { + +TEST(DataAccessorTest, CreateDataAccessor) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + DataAccessor<int> testdata(test_value, testSet_lock_); + int data_from_testdata = testdata.GetData(); + + //assert + EXPECT_EQ(test_value, data_from_testdata); +} + +TEST(DataAccessorTest, CreateDataAccessor_MutexIsLocked_CannotLockItAgain) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + DataAccessor<int> testdata(test_value, testSet_lock_); + + //assert + EXPECT_FALSE(testSet_lock_.Try()); +} + +TEST(DataAccessorTest, CopyDataAccessor_GetDataFromDataAccessors) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + DataAccessor<int> testdata(test_value, testSet_lock_); + DataAccessor<int> testdata_copy(testdata); + + int data_from_testdata = testdata.GetData(); + int data_from_testdata_copy = testdata_copy.GetData(); + + //assert + EXPECT_EQ(data_from_testdata, data_from_testdata_copy); + + EXPECT_FALSE(testSet_lock_.Try()); +} + +TEST(DataAccessorTest,ChangedDataInDataAccessor_ChangeData_DataInDataAccessorIsChanged) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + DataAccessor<int> testdata(test_value, testSet_lock_); + test_value = 0; + + int data_from_testdata_after_change = testdata.GetData(); + + //assert + EXPECT_EQ(test_value, data_from_testdata_after_change); +} + +TEST(DataAccessorTest, DeleteDataAccessor_CreatedOneDeleteOneThread_MutexIsUnlocked) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + { + DataAccessor<int> testdata(test_value, testSet_lock_); + + //assert + EXPECT_FALSE(testSet_lock_.Try()); + } + //assert + + EXPECT_TRUE(testSet_lock_.Try()); + + testSet_lock_.Release(); + +} + +TEST(DataAccessorTest, DeleteDataAccessor_CreatedThreadAndCopyDeleteBothThreads_MutexIsUnlocked) { + + //arrange + int test_value = 10; + sync_primitives::Lock testSet_lock_; + { + DataAccessor<int> testdata(test_value, testSet_lock_); + { + DataAccessor<int> testdata_copy(testdata); + + //assert + EXPECT_FALSE(testSet_lock_.Try()); + } + //assert + EXPECT_FALSE(testSet_lock_.Try()); + + } + + //assert + EXPECT_TRUE(testSet_lock_.Try()); + testSet_lock_.Release(); + +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/date_time_test.cc b/src/components/utils/test/date_time_test.cc index ddcf679a16..b437bdc17e 100644 --- a/src/components/utils/test/date_time_test.cc +++ b/src/components/utils/test/date_time_test.cc @@ -1,126 +1,326 @@ /* -* Copyright (c) 2014, Ford Motor Company -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following -* disclaimer in the documentation and/or other materials provided with the -* distribution. -* -* Neither the name of the Ford Motor Company nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -*/ - -#include <unistd.h> + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ #include "gtest/gtest.h" -#include "gmock/gmock.h" - #include "utils/date_time.h" -namespace test { -namespace components { -namespace utils { +namespace test { +namespace components { +namespace utils { +using namespace date_time; TEST(DateTimeTest, GetCurrentTime) { + + //arrange const TimevalStruct time1 = date_time::DateTime::getCurrentTime(); + + //assert ASSERT_NE(0, time1.tv_sec); ASSERT_GE(time1.tv_usec, 0); + //act const TimevalStruct time2 = date_time::DateTime::getCurrentTime(); + + //assert ASSERT_NE(0, time2.tv_sec); ASSERT_GE(time2.tv_usec, 0); - ASSERT_GE(time2.tv_sec, time1.tv_sec); + ASSERT_GE(time2.tv_sec, time1.tv_sec); +} + +TEST(DateTimeTest, GetSecs) { + //arrange + TimevalStruct time; + time.tv_sec = 1; + time.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + //assert + ASSERT_EQ(1, date_time::DateTime::getSecs(time)); } TEST(DateTimeTest, GetmSecs) { + //arrange TimevalStruct time; - time.tv_sec = 1; + time.tv_sec = 1; time.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; - ASSERT_EQ(time.tv_sec * date_time::DateTime::MILLISECONDS_IN_SECOND + - time.tv_usec / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS, - date_time::DateTime::getmSecs(time)); + int64_t expect_value = time.tv_sec + * date_time::DateTime::MILLISECONDS_IN_SECOND + + time.tv_usec / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + //assert + ASSERT_EQ(expect_value, date_time::DateTime::getmSecs(time)); } TEST(DateTimeTest, GetuSecs) { + //arrange TimevalStruct time; - time.tv_sec = 3; + time.tv_sec = 3; time.tv_usec = 4; - ASSERT_EQ(time.tv_sec * date_time::DateTime::MILLISECONDS_IN_SECOND * - date_time::DateTime::MICROSECONDS_IN_MILLISECONDS + time.tv_usec, - date_time::DateTime::getuSecs(time)); + int64_t expect_value = time.tv_sec + * date_time::DateTime::MILLISECONDS_IN_SECOND + * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS + time.tv_usec; + //assert + ASSERT_EQ(expect_value, date_time::DateTime::getuSecs(time)); } TEST(DateTimeTest, GetuSecsmSecs) { + //arrange TimevalStruct time; - time.tv_sec = 5; + time.tv_sec = 5; time.tv_usec = 6; - ASSERT_EQ( date_time::DateTime::getmSecs(time), - date_time::DateTime::getuSecs(time) / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS); + int64_t expect_value = date_time::DateTime::getuSecs(time) + / date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + //assert + ASSERT_EQ(expect_value, date_time::DateTime::getmSecs(time)); } TEST(DateTimeTest, CalculateTimeSpan) { + //arrange const TimevalStruct time = date_time::DateTime::getCurrentTime(); const uint32_t sleep_time_mSec = 10; usleep(sleep_time_mSec * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS); - ASSERT_GE(date_time::DateTime::calculateTimeSpan(time), - sleep_time_mSec); + //assert + ASSERT_GE(date_time::DateTime::calculateTimeSpan(time), sleep_time_mSec); } TEST(DateTimeTest, CalculateTimeDiff) { + + //arrange TimevalStruct time1; - time1.tv_sec = 1; + time1.tv_sec = 1; time1.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; TimevalStruct time2; - time2.tv_sec = 3; + time2.tv_sec = 3; time2.tv_usec = 4 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; //time2 to time1 TimevalStruct diff1; - diff1.tv_sec = time2.tv_sec - time1.tv_sec; + diff1.tv_sec = time2.tv_sec - time1.tv_sec; diff1.tv_usec = time2.tv_usec - time1.tv_usec; const int64_t mSecDiff = static_cast<int64_t>(diff1.tv_sec) * 1000 + diff1.tv_usec / 1000; - ASSERT_EQ(mSecDiff, - date_time::DateTime::calculateTimeDiff(time2, time1)); + //assert + ASSERT_EQ(mSecDiff, date_time::DateTime::calculateTimeDiff(time2, time1)); //time1 to time2 TimevalStruct diff2; - diff2.tv_sec = time1.tv_sec - time2.tv_sec; + diff2.tv_sec = time1.tv_sec - time2.tv_sec; diff2.tv_usec = time1.tv_usec - time2.tv_usec; const int64_t mSecDiff2 = -(static_cast<int64_t>(diff2.tv_sec) * 1000 + diff2.tv_usec / 1000); - ASSERT_EQ(mSecDiff2, - date_time::DateTime::calculateTimeDiff(time1, time2)); + //assert + ASSERT_EQ(mSecDiff2, date_time::DateTime::calculateTimeDiff(time1, time2)); +} + +TEST(DateTimeTest, CalculateEqualTimeDiff) { + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + TimevalStruct time2; + time2.tv_sec = 1; + time2.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + ASSERT_EQ(0, date_time::DateTime::calculateTimeDiff(time2, time1)); + ASSERT_EQ(0, date_time::DateTime::calculateTimeDiff(time1, time2)); +} + +TEST(DateTimeTest, compareTime) { + + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + TimevalStruct time2; + time2.tv_sec = 2; + time2.tv_usec = 4 * date_time::DateTime::MICROSECONDS_IN_MILLISECONDS; + + //assert + ASSERT_EQ(LESS, date_time::DateTime::compareTime(time1, time2)); + ASSERT_EQ(GREATER, date_time::DateTime::compareTime(time2, time1)); + ASSERT_NE(EQUAL, date_time::DateTime::compareTime(time2, time1)); + + //act + TimevalStruct time3 = date_time::DateTime::Sub(time2, time1); + + //assert + ASSERT_EQ(EQUAL, date_time::DateTime::compareTime(time1, time3)); +} + +//TODO(VVeremjova) APPLINK-11051 Missing convertation microseconds in seconds + +TEST(DateTimeTest, DISABLED_GetSecs_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 0; + time1.tv_usec = date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_EQ(1, date_time::DateTime::getSecs(time1)); +} + +TEST(DateTimeTest, DISABLED_compareTime_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 0; + time2.tv_usec = date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_EQ(1, date_time::DateTime::getSecs(time1)); + ASSERT_EQ(1, date_time::DateTime::getSecs(time2)); + ASSERT_EQ(EQUAL, date_time::DateTime::compareTime(time1, time2)); +} + +TEST(DateTimeTest, DISABLED_compareEqualTime_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 0; + time2.tv_usec = date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_TRUE(date_time::DateTime::Equal(time1, time2)); +} + +TEST(DateTimeTest, DISABLED_compareLessTime_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 0; + time2.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_TRUE(date_time::DateTime::Less(time1, time2)); +} + +TEST(DateTimeTest, DISABLED_compareGreaterTime_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 0; + time2.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_TRUE(date_time::DateTime::Greater(time2, time1)); +} + +TEST(DateTimeTest, DISABLED_CalculateTimeSub_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 1; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 0; + time2.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + TimevalStruct time3 = date_time::DateTime::Sub(time2, time1); + + //assert + ASSERT_EQ(EQUAL, date_time::DateTime::compareTime(time1, time3)); +} + +TEST(DateTimeTest, DISABLED_CalculateTimeDiff_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 2; + time1.tv_usec = 5 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + TimevalStruct time2; + time2.tv_sec = 3; + time2.tv_usec = 1 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_EQ(3000, date_time::DateTime::calculateTimeDiff(time2, time1)); + ASSERT_EQ(3000, date_time::DateTime::calculateTimeDiff(time1, time2)); +} + +TEST(DateTimeTest, DISABLED_CalculateEqualTimeDiff_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 2; + time1.tv_usec = 2 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + TimevalStruct time2; + time2.tv_sec = 3; + time2.tv_usec = 1 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + //assert + ASSERT_EQ(0, date_time::DateTime::calculateTimeDiff(time2, time1)); + ASSERT_EQ(0, date_time::DateTime::calculateTimeDiff(time1, time2)); +} + +TEST(DateTimeTest, DISABLED_CalculateEqualTimeSub_UsecConvertedInSec) { + //arrange + TimevalStruct time1; + time1.tv_sec = 3; + time1.tv_usec = 0; + + TimevalStruct time2; + time2.tv_sec = 2; + time2.tv_usec = 1 * date_time::DateTime::MICROSECONDS_IN_SECOND; + + TimevalStruct time3 = date_time::DateTime::Sub(time2, time1); + TimevalStruct time4 = date_time::DateTime::Sub(time1, time2); + + TimevalStruct time_expected; + time_expected.tv_sec = 0; + + //assert + ASSERT_EQ(EQUAL, date_time::DateTime::compareTime(time_expected, time3)); + ASSERT_EQ(EQUAL, date_time::DateTime::compareTime(time_expected, time4)); } } // namespace utils diff --git a/src/components/utils/test/file_system_test.cc b/src/components/utils/test/file_system_test.cc index abf09735ba..54a662c511 100644 --- a/src/components/utils/test/file_system_test.cc +++ b/src/components/utils/test/file_system_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,82 +30,1146 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "gmock/gmock.h" +#include <algorithm> +#include <fstream> +#include "gtest/gtest.h" #include "utils/file_system.h" -namespace test { -namespace components { -namespace utils { +namespace test { +namespace components { +namespace utils { -TEST(FileSystemTest, CommonFileSystemTest) { - // Directory creation - ASSERT_FALSE(file_system::DirectoryExists("./Test directory")); +using namespace file_system; - file_system::CreateDirectory("./Test directory"); +TEST(FileSystemTest, CreateDeleteDirectory) { - ASSERT_TRUE(file_system::DirectoryExists("./Test directory")); + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Directory creation + CreateDirectory("./Test directory"); - ASSERT_TRUE(file_system::IsDirectory("./Test directory")); + EXPECT_TRUE(DirectoryExists("./Test directory")); + EXPECT_TRUE(IsDirectory("./Test directory")); + // Directory removing + EXPECT_TRUE(RemoveDirectory("./Test directory", false)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, CreateDirectoryTwice) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Directory creation + CreateDirectory("./Test directory"); + + EXPECT_TRUE(DirectoryExists("./Test directory")); + EXPECT_TRUE(IsDirectory("./Test directory")); + + // Create directory second time + CreateDirectory("./Test directory"); + EXPECT_TRUE(DirectoryExists("./Test directory")); + + // Directory removing + EXPECT_TRUE(RemoveDirectory("./Test directory", false)); + //try delete directory again + EXPECT_FALSE(RemoveDirectory("./Test directory", false)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest,DeleteDirectoryRecursively) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Create directories + CreateDirectory("./Test directory"); + CreateDirectory("./Test directory/Test directory 2"); + + // Create file inside directory + EXPECT_TRUE(CreateFile("./Test directory/test file")); + + EXPECT_FALSE(RemoveDirectory("./Test directory", false)); + EXPECT_TRUE(DirectoryExists("./Test directory")); + EXPECT_TRUE(IsDirectory("./Test directory")); + + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, CreateDirectoryRecursivelyDeleteRecursively) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Create directories recursively + CreateDirectoryRecursively( + "./Test directory/Test directory 2/Test directory 3"); + + EXPECT_TRUE(DirectoryExists("./Test directory")); + EXPECT_TRUE(IsDirectory("./Test directory")); + + EXPECT_TRUE(DirectoryExists("./Test directory/Test directory 2")); + EXPECT_TRUE(IsDirectory("./Test directory/Test directory 2")); + + EXPECT_TRUE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); + EXPECT_TRUE( + IsDirectory("./Test directory/Test directory 2/Test directory 3")); + + // Delete recursively + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); + EXPECT_FALSE(DirectoryExists("./Test directory/Test directory 2")); + EXPECT_FALSE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); +} + +TEST(FileSystemTest, TwiceCreateDirectoryRecursivelyDeleteRecursivelyOnce) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Create directories recursively + EXPECT_TRUE( + CreateDirectoryRecursively( + "./Test directory/Test directory 2/Test directory 3")); + + // Check that all directories are created + EXPECT_TRUE(DirectoryExists("./Test directory")); + EXPECT_TRUE(IsDirectory("./Test directory")); + + EXPECT_TRUE(DirectoryExists("./Test directory/Test directory 2")); + EXPECT_TRUE(IsDirectory("./Test directory/Test directory 2")); + + EXPECT_TRUE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); + EXPECT_TRUE( + IsDirectory("./Test directory/Test directory 2/Test directory 3")); + + // Create directories recursively second time + EXPECT_TRUE( + CreateDirectoryRecursively( + "./Test directory/Test directory 2/Test directory 3")); + + EXPECT_TRUE(DirectoryExists("./Test directory")); + + EXPECT_TRUE(DirectoryExists("./Test directory/Test directory 2")); + + EXPECT_TRUE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); + + // Delete recursively + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); + // Delete recursively again is impossible + EXPECT_FALSE(RemoveDirectory("./Test directory", true)); + + EXPECT_FALSE(DirectoryExists("./Test directory")); + EXPECT_FALSE(DirectoryExists("./Test directory/Test directory 2")); + EXPECT_FALSE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); +} + +TEST(FileSystemTest, CreateDeleteFile) { + ASSERT_FALSE(FileExists("./test file")); // File creation - ASSERT_FALSE(file_system::FileExists("./Test directory/test file")); + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_FALSE(IsDirectory("./test file")); - std::vector<unsigned char> data; - data.push_back('t'); - data.push_back('e'); - data.push_back('s'); - data.push_back('t'); + // Delete file + EXPECT_TRUE(DeleteFile("./test file")); + //try delete file again + EXPECT_FALSE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CheckIsDirectory) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + // Create directory and check that IsDirectory=true + CreateDirectory("./Test directory"); + EXPECT_TRUE(IsDirectory("./Test directory")); + + // Delete directory and check, that IsDirectory=false + EXPECT_TRUE(RemoveDirectory("./Test directory", false)); + EXPECT_FALSE(DirectoryExists("./Test directory")); + EXPECT_FALSE(IsDirectory("./Test directory")); + + // Create file and check that IsDirectory=false + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_FALSE(IsDirectory("./test file")); + + // Delete file and check that IsDirectory=false + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); + EXPECT_FALSE(IsDirectory("./test file")); +} - ASSERT_TRUE(file_system::Write("./Test directory/test file", data)); +TEST(FileSystemTest, CreateFileTwice) { + ASSERT_FALSE(FileExists("./test file")); - ASSERT_TRUE(file_system::FileExists("./Test directory/test file")); + // Create file first time + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); - ASSERT_FALSE(file_system::IsDirectory("./Test directory/test file")); + // Create file second time + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); + + // Delete file + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateOpenCloseFileStream) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + Close(test_file); + EXPECT_FALSE(test_file->is_open()); + delete test_file; + + EXPECT_TRUE(FileExists("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateAndOpenFileStreamTwice) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + Close(test_file); + EXPECT_FALSE(test_file->is_open()); + delete test_file; + + EXPECT_TRUE(FileExists("./test file")); + + // Create file second time + EXPECT_TRUE(CreateFile("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, OpenFileWriteInFileStream) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + // Write data in file + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + EXPECT_TRUE(Write(test_file, data, data_size)); + Close(test_file); + EXPECT_FALSE(test_file->is_open()); + delete test_file; // Read data from file - std::vector<unsigned char> result; + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + +// Check data + for (uint i = 0; i < data_size; ++i) { + EXPECT_EQ(data[i], result[i]); + } + delete data; - ASSERT_TRUE(file_system::ReadBinaryFile("./Test directory/test file", - result)); - ASSERT_FALSE(result.empty()); + // Delete file + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} - // list files - ASSERT_TRUE(file_system::Write("./Test directory/test file 2", data)); +TEST(FileSystemTest, CannotWriteInClosedFileStream) { + ASSERT_FALSE(FileExists("./test file")); - std::vector<std::string> list; - list = file_system::ListFiles("./Test directory"); + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + Close(test_file); + EXPECT_FALSE(test_file->is_open()); - ASSERT_FALSE(list.empty()); - std::sort(list.begin(), list.end()); - ASSERT_EQ("test file", list[0]); - ASSERT_EQ("test file 2", list[1]); + // Write data in file + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + EXPECT_TRUE(Write(test_file, data, data_size)); + + delete data; + delete test_file; + + // Read data from file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_TRUE(result.empty()); // Delete file - ASSERT_TRUE(file_system::FileExists("./Test directory/test file 2")); - ASSERT_TRUE(file_system::DeleteFile("./Test directory/test file 2")); - ASSERT_FALSE(file_system::FileExists("./Test directory/test file 2")); + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateWriteInFileStream_CreateFileAgain_FileRewritten) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); - // Delete empty directory - file_system::CreateDirectory("./Test directory/Empty directory"); + // Write data in file + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + EXPECT_TRUE(Write(test_file, data, data_size)); - ASSERT_TRUE(file_system::DirectoryExists( - "./Test directory/Empty directory")); - ASSERT_TRUE(file_system::RemoveDirectory( - "./Test directory/Empty directory", false)); - ASSERT_FALSE(file_system::DirectoryExists( - "./Test directory/Empty directory")); + Close(test_file); + delete test_file; - ASSERT_FALSE(file_system::RemoveDirectory("./Test directory", false)); - ASSERT_TRUE(file_system::DirectoryExists("./Test directory")); + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); - // Delete directory recursively - file_system::CreateDirectory("./Test directory/Test directory 2"); - ASSERT_TRUE(file_system::Write( - "./Test directory/Test directory 2/test file 2", data)); - ASSERT_TRUE(file_system::RemoveDirectory("./Test directory", true)); + delete data; + EXPECT_TRUE(CreateFile("./test file")); - ASSERT_FALSE(file_system::DirectoryExists("./Test directory")); + // Now file is empty + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_TRUE(result.empty()); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); } + +TEST(FileSystemTest, CreateFileStream_WriteInFile_FileStreamNotClosed) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + // Write data in file + uint32_t data_size = 4; + std::vector < uint8_t > data; + for (uint i = 0; i < data_size; ++i) { + data.push_back(i); + } + // Write data in file + EXPECT_TRUE(Write("./test file", data)); + EXPECT_TRUE(test_file->is_open()); + + // Close filestream + Close(test_file); + delete test_file; + + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateFileStream_WriteInFileWriteInFileStream_FileIncludeLastData) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + // Write data in file + uint32_t data_size = 4; + std::vector < uint8_t > data; + for (uint i = 0; i < data_size; ++i) { + data.push_back(i); + } + // Write data in file + EXPECT_TRUE(Write("./test file", data)); + + EXPECT_TRUE(test_file->is_open()); + + // Write in filestream + uint8_t* data_2 = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data_2[i] = i + data_size; + } + EXPECT_TRUE(Write(test_file, data_2, data_size)); + // Close filestream + Close(test_file); + + delete test_file; + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Check data + EXPECT_EQ(result.size(), data_size); + for (uint i = 0; i < data_size; ++i) { + EXPECT_NE(data[i], result[i]); + EXPECT_EQ(data_2[i], result[i]); + } + + delete data_2; + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteInFilestreamTwice_FileRewritten) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + // Open file second time + std::ofstream* test_file_2 = Open("./test file"); + EXPECT_TRUE(test_file_2->is_open()); + + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + uint8_t* data_2 = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data_2[i] = i + 4; + } + + // Write data in file + EXPECT_TRUE(Write(test_file, data, data_size)); + + EXPECT_TRUE(Write(test_file_2, data_2, data_size)); + + Close(test_file); + Close(test_file_2); + + EXPECT_FALSE(test_file->is_open()); + EXPECT_FALSE(test_file_2->is_open()); + + delete test_file; + delete test_file_2; + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + // Check data + for (uint i = 0; i < data_size; ++i) { + EXPECT_NE(data[i], result[i]); + EXPECT_EQ(data_2[i], result[i]); + } + + delete data; + delete data_2; + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteInFilestreamConsequentially_FileRewritten) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + + // Write data in file + EXPECT_TRUE(Write(test_file, data, data_size)); + + Close(test_file); + EXPECT_FALSE(test_file->is_open()); + + // Open file second time + std::ofstream* test_file_2 = Open("./test file"); + EXPECT_TRUE(test_file_2->is_open()); + + // Write second time + uint8_t* data_2 = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data_2[i] = i + 4; + } + EXPECT_TRUE(Write(test_file_2, data_2, data_size)); + + Close(test_file_2); + EXPECT_FALSE(test_file_2->is_open()); + + delete test_file; + delete test_file_2; + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Check data + EXPECT_EQ(result.size(), data_size); + for (uint i = 0; i < data_size; ++i) { + EXPECT_NE(data[i], result[i]); + EXPECT_EQ(data_2[i], result[i]); + } + + delete data; + delete data_2; + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateFileTwiceWriteInFileTwice) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); + + uint32_t data_size = 4; + std::vector < uint8_t > data; + for (uint i = 0; i < data_size; ++i) { + data.push_back(i); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data)); + // Create file second time + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + + std::vector < uint8_t > data_2; + for (uint i = 0; i < data_size; ++i) { + data_2.push_back(i + data_size); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data_2)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + EXPECT_EQ(data_2, result); + EXPECT_EQ(result.size(), data_size); + // Check data + for (uint i = 0; i < data_size; ++i) { + EXPECT_NE(data[i], result[i]); + EXPECT_EQ(data_2[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteInFileTwiceFileRewritten) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); + + // Write data in file + uint32_t data_size = 4; + std::vector < uint8_t > data; + for (uint i = 0; i < data_size; ++i) { + data.push_back(i); + } + EXPECT_TRUE(Write("./test file", data)); + + // Write data to file again + std::vector < uint8_t > data_2; + for (uint i = 0; i < data_size; ++i) { + data_2.push_back(i + data_size); + } + EXPECT_TRUE(Write("./test file", data_2)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Check data + EXPECT_EQ(data_size, result.size()); + for (uint i = 0; i < data_size; ++i) { + EXPECT_NE(data[i], result[i]); + EXPECT_EQ(data_2[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteDataInTheEndOfFile) { + ASSERT_FALSE(FileExists("./test file")); + + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); + + int32_t data_size = 4; + std::vector < uint8_t > data; + for (int i = 0; i < data_size; ++i) { + data.push_back(i); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data)); + + // Write in file second time + std::vector < uint8_t > data_2; + for (int i = 0; i < data_size; ++i) { + data_2.push_back(i + data_size); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data_2, std::ios_base::app)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + std::vector < uint8_t > data_check; + for (int i = 0; i < 2 * data_size; ++i) { + data_check.push_back(i); + } + + // Check data + EXPECT_EQ(data_check.size(), result.size()); + for (int i = 0; i < 2 * data_size; ++i) { + EXPECT_EQ(data_check[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteInFileStream_WriteInFileInTheEndOfFile_FileIncludeBothData) { + ASSERT_FALSE(FileExists("./test file")); + + // Create and open file + std::ofstream* test_file = Open("./test file"); + EXPECT_TRUE(test_file->is_open()); + + // Write data in file + uint32_t data_size = 4; + std::vector < uint8_t > data; + for (uint i = 0; i < data_size; ++i) { + data.push_back(i); + } + // Write data in file + EXPECT_TRUE(Write("./test file", data)); + EXPECT_TRUE(test_file->is_open()); + + // Close filestream + Close(test_file); + + delete test_file; + // Write in file second time + std::vector < uint8_t > data_2; + for (uint i = 0; i < data_size; ++i) { + data_2.push_back(i + data_size); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data_2, std::ios_base::app)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + std::vector < uint8_t > data_check; + for (uint i = 0; i < 2 * data_size; ++i) { + data_check.push_back(i); + } + + // Check data + EXPECT_EQ(data_check.size(), result.size()); + for (uint i = 0; i < 2 * data_size; ++i) { + EXPECT_EQ(data_check[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, OpenFileStreamForRead_WriteInFileStream) { + ASSERT_FALSE(FileExists("./test file")); + // File creation + EXPECT_TRUE(CreateFile("./test file")); + std::ofstream* test_file = Open("./test file", std::ios_base::in); + EXPECT_TRUE(test_file->is_open()); + + // Write data in file + uint32_t data_size = 4; + uint8_t* data = new uint8_t[data_size]; + for (uint i = 0; i < data_size; ++i) { + data[i] = i; + } + + EXPECT_TRUE(Write(test_file, data, data_size)); + + Close(test_file); + EXPECT_FALSE(test_file->is_open()); + + // Read data from file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Check data + for (uint i = 0; i < data_size; ++i) { + EXPECT_EQ(data[i], result[i]); + } + + delete data; + delete test_file; + + EXPECT_TRUE(FileExists("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteFileNotExists) { + ASSERT_FALSE(FileExists("./test file")); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(Write("./test file", data)); + // File now exists + ASSERT_TRUE(FileExists("./test file")); + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteFileReadFile) { + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(Write("./test file", data)); + + // Read data from file + std::string result; + std::string check = "test"; + EXPECT_TRUE(ReadFile("./test file", result)); + EXPECT_NE(0, result.size()); + EXPECT_EQ(check, result); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteBinaryDataReadBinaryFile) { + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + + uint8_t tmp[] = { 1, 2, 3, 4}; + std::vector<uint8_t> data(tmp, tmp + 4); + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + + // Read data from file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + EXPECT_EQ(data, result); + + EXPECT_TRUE(DeleteFile("./test file")); +} + +TEST(FileSystemTest, WriteBinaryDataTwice_FileRewritten) { + ASSERT_FALSE(FileExists("./test file")); + + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_TRUE(FileExists("./test file")); + + int32_t data_size = 4; + std::vector < uint8_t > data; + for (int i = 0; i < data_size; ++i) { + data.push_back(i); + } + // Write data in file + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + + // Write in file second time + std::vector < uint8_t > data_2; + for (int i = 0; i < data_size; ++i) { + data_2.push_back(i + data_size); + } + + // Write data in file + EXPECT_TRUE(WriteBinaryFile("./test file", data_2)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Check data + EXPECT_EQ(data_2.size(), result.size()); + for (int i = 0; i < data_size; ++i) { + EXPECT_EQ(data_2[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteBinaryDataFileNotExists) { + ASSERT_FALSE(FileExists("./test file")); + + int32_t data_size = 4; + std::vector < uint8_t > data; + for (int i = 0; i < data_size; ++i) { + data.push_back(i); + } + + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + ASSERT_TRUE(FileExists("./test file")); + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteDataAsBinaryData) { + ASSERT_FALSE(FileExists("./test file")); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + ASSERT_TRUE(FileExists("./test file")); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + EXPECT_EQ(data.size(), result.size()); + + for (uint i = 0; i < result.size(); ++i) { + EXPECT_EQ(data[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteEmptyData) { + ASSERT_FALSE(FileExists("./test file")); + + std::vector<unsigned char> data; + EXPECT_TRUE(Write("./test file", data)); + ASSERT_TRUE(FileExists("./test file")); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_TRUE(result.empty()); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteEmptyDataAsBinaryData) { + ASSERT_FALSE(FileExists("./test file")); + + // Write empty data + std::vector<unsigned char> data; + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + ASSERT_TRUE(FileExists("./test file")); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_TRUE(result.empty()); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteBinaryData_WriteDataInTheEndOfFile) { + ASSERT_FALSE(FileExists("./test file")); + + // Write binary file + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + ASSERT_TRUE(FileExists("./test file")); + + // Write in file second time + int32_t data_size = 4; + std::vector < uint8_t > data_2; + for (int i = 0; i < data_size; ++i) { + data_2.push_back(i); + } + + // Write data in file + EXPECT_TRUE(Write("./test file", data_2, std::ios_base::app)); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Prepare data for check + data.insert(data.end(), data_2.begin(), data_2.end()); + + // Compare data + EXPECT_EQ(data.size(), result.size()); + for (uint i = 0; i < result.size(); ++i) { + EXPECT_EQ(data[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateFile_WriteDataWithFlagOpenForReading) { + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + // Write data in file + int32_t data_size = 4; + std::vector < uint8_t > data; + for (int i = 0; i < data_size; ++i) { + data.push_back(i); + } + EXPECT_TRUE(Write("./test file", data, std::ios_base::in)); + EXPECT_TRUE(FileExists("./test file")); + + // Check file + std::vector < uint8_t > result; + EXPECT_TRUE(ReadBinaryFile("./test file", result)); + EXPECT_FALSE(result.empty()); + + // Compare data + EXPECT_EQ(data.size(), result.size()); + for (uint i = 0; i < result.size(); ++i) { + EXPECT_EQ(data[i], result[i]); + } + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, FileDoesNotCreated_WriteFileWithFlagOpenForReadingIsImpossible) { + ASSERT_FALSE(FileExists("./test file")); + + // Write data in file is impossible + int32_t data_size = 4; + std::vector < uint8_t > data; + for (int i = 0; i < data_size; ++i) { + data.push_back(i); + } + EXPECT_FALSE(Write("./test file", data, std::ios_base::in)); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, WriteFileGetSize) { + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + EXPECT_EQ(0, FileSize("./test file")); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(Write("./test file", data)); + + EXPECT_NE(0, FileSize("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, CreateFileCheckDefaultAccess) { + // File creation + ASSERT_FALSE(FileExists("./test file")); + EXPECT_TRUE(CreateFile("./test file")); + + // Check accesses + EXPECT_TRUE(IsAccessible("./test file", R_OK)); + EXPECT_TRUE(IsAccessible("./test file", W_OK)); + EXPECT_TRUE(IsReadingAllowed("./test file")); + EXPECT_TRUE(IsWritingAllowed("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); +} + +TEST(FileSystemTest, GetFileModificationTime) { + ASSERT_FALSE(FileExists("./test file")); + + EXPECT_TRUE(CreateFile("./test file")); + + uint64_t modif_time = GetFileModificationTime("./test file"); + EXPECT_LE(0, modif_time); + + std::vector < uint8_t > data(1, 1); + EXPECT_TRUE(WriteBinaryFile("./test file", data)); + + EXPECT_LE(0, GetFileModificationTime("./test file")); + EXPECT_LE(modif_time, GetFileModificationTime("./test file")); + + EXPECT_TRUE(DeleteFile("./test file")); + EXPECT_FALSE(FileExists("./test file")); + +} + +TEST(FileSystemTest, ListFiles) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectory("./Test directory"); + + std::vector < std::string > list; + list = ListFiles("./Test directory"); + EXPECT_TRUE(list.empty()); + + EXPECT_TRUE(CreateFile("./Test directory/test file")); + EXPECT_TRUE(CreateFile("./Test directory/test file 2")); + + list = ListFiles("./Test directory"); + EXPECT_FALSE(list.empty()); + + std::sort(list.begin(), list.end()); + EXPECT_EQ("test file", list[0]); + EXPECT_EQ("test file 2", list[1]); + + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); + + EXPECT_FALSE(FileExists("./Test directory/test file")); + EXPECT_FALSE(FileExists("./Test directory/test file 2")); +} + +TEST(FileSystemTest, ListFilesIncludeSubdirectory) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectoryRecursively("./Test directory/Test directory 2/"); + + std::vector < std::string > list; + list = ListFiles("./Test directory"); + EXPECT_FALSE(list.empty()); + EXPECT_EQ(1, list.size()); + EXPECT_EQ("Test directory 2", list[0]); + + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, ListFilesDoesNotIncludeFilesInSubdirectory) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectoryRecursively("./Test directory/Test directory 2/"); + + std::vector < std::string > list; + list = ListFiles("./Test directory"); + EXPECT_FALSE(list.empty()); + + EXPECT_TRUE(CreateFile("./Test directory/Test directory 2/test file")); + EXPECT_TRUE(CreateFile("./Test directory/Test directory 2/test file 2")); + + list = ListFiles("./Test directory"); + EXPECT_FALSE(list.empty()); + + std::sort(list.begin(), list.end()); + EXPECT_EQ("Test directory 2", list[0]); + EXPECT_EQ(1, list.size()); + + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, GetAvailableDiskSpace) { + + // Get available disk space before directory with file creaction and after + uint64_t available_space = GetAvailableDiskSpace("."); + EXPECT_NE(0, available_space); + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectory("./Test directory"); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + EXPECT_TRUE(Write("./Test directory/test file", data)); + + EXPECT_GE(available_space, GetAvailableDiskSpace(".")); + EXPECT_TRUE(RemoveDirectory("./Test directory")); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, ConvertPathForURL) { + std::string path = "./Test directory"; + EXPECT_NE(path, ConvertPathForURL(path)); + std::string path_brackets = "./Test_directory_with(brackets)"; + EXPECT_NE(path_brackets, ConvertPathForURL(path)); + std::string another_path = "./Test_directory/new_directory_without_spaces"; + EXPECT_EQ(another_path, ConvertPathForURL(another_path)); +} + +TEST(FileSystemTest, DirectorySize) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectory("./Test directory"); + EXPECT_TRUE(DirectoryExists("./Test directory")); + // Get size of empty directory + EXPECT_EQ(0, DirectorySize("./Test directory")); + EXPECT_TRUE(CreateFile("./Test directory/test file")); + + // Get size of nonempty directory with empty file + EXPECT_EQ(0, DirectorySize("./Test directory")); + + unsigned char tmp[] = { 't', 'e', 's', 't' }; + std::vector<unsigned char> data(tmp, tmp + 4); + + EXPECT_TRUE(Write("./Test directory/test file", data)); + // Get size of nonempty directory with nonempty file + EXPECT_NE(0, DirectorySize("./Test directory")); + + EXPECT_TRUE(DeleteFile("./Test directory/test file")); + EXPECT_EQ(0, DirectorySize("./Test directory")); + EXPECT_TRUE(RemoveDirectory("./Test directory")); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + +TEST(FileSystemTest, DeleteAllContentInDirectory) { + ASSERT_FALSE(DirectoryExists("./Test directory")); + CreateDirectory("./Test directory"); + + // Create files in directory + EXPECT_TRUE(CreateFile("./Test directory/test file")); + EXPECT_TRUE(CreateFile("./Test directory/test file 2")); + + EXPECT_TRUE(FileExists("./Test directory/test file")); + EXPECT_TRUE(FileExists("./Test directory/test file 2")); + + EXPECT_TRUE(DirectoryExists("./Test directory")); + + // Create subdirectories + CreateDirectoryRecursively( + "./Test directory/Test directory 2/Test directory 3"); + + EXPECT_TRUE(DirectoryExists("./Test directory/Test directory 2")); + EXPECT_TRUE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); + + remove_directory_content("./Test directory"); + + // Directory does not include files and subdirectories + EXPECT_FALSE(FileExists("./Test directory/test file")); + EXPECT_FALSE(FileExists("./Test directory/test file 2")); + + EXPECT_FALSE( + DirectoryExists("./Test directory/Test directory 2/Test directory 3")); + EXPECT_FALSE(DirectoryExists("./Test directory/Test directory 2")); + + std::vector < std::string > list; + list = ListFiles("./Test directory"); + EXPECT_TRUE(list.empty()); + + EXPECT_TRUE(DirectoryExists("./Test directory")); + + EXPECT_TRUE(RemoveDirectory("./Test directory", true)); + EXPECT_FALSE(DirectoryExists("./Test directory")); +} + } // namespace utils } // namespace components } // namespace test diff --git a/src/components/utils/test/lock_posix_test.cc b/src/components/utils/test/lock_posix_test.cc new file mode 100644 index 0000000000..9b0d9533bc --- /dev/null +++ b/src/components/utils/test/lock_posix_test.cc @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/lock.h" + +namespace test { +namespace components { +namespace utils { + +using sync_primitives::Lock; + +TEST(LockPosixTest, DefaultCtorTest_ExpectNonRecursiveMutexCreated) { + // Create Lock object + Lock test_mutex; + // Lock mutex + test_mutex.Acquire(); + // Check if created mutex is non-recursive + EXPECT_FALSE(test_mutex.Try()); + // Release mutex before destroy + test_mutex.Release(); +} + +TEST(LockPosixTest, CtorTestWithFalseArgument_ExpectNonRecursiveMutexCreated) { + // Create Lock object + Lock test_mutex(false); + // Lock mutex + test_mutex.Acquire(); + // Check if created mutex is non-recursive + EXPECT_FALSE(test_mutex.Try()); + // Release mutex before destroy + test_mutex.Release(); +} + +TEST(LockPosixTest, CtorTestWithTrueArgument_ExpectRecursiveMutexCreated) { + // Create Lock object + Lock test_mutex(true); + // Lock mutex + test_mutex.Acquire(); + // Check if created mutex is recursive + EXPECT_TRUE(test_mutex.Try()); + // Release mutex before destroy + test_mutex.Release(); + test_mutex.Release(); +} + +TEST(LockPosixTest, AcquireMutex_ExpectMutexLocked) { + // Create Lock object (non-recursive mutex) + Lock test_mutex; + // Lock mutex + test_mutex.Acquire(); + // Try to lock it again. If locked expect false + EXPECT_FALSE(test_mutex.Try()); + test_mutex.Release(); +} + +TEST(LockPosixTest, ReleaseMutex_ExpectMutexReleased) { + // Create Lock object (non-recursive mutex) + Lock test_mutex; + // Lock mutex + test_mutex.Acquire(); + // Release mutex + test_mutex.Release(); + // Try to lock it again. If released expect true + EXPECT_TRUE(test_mutex.Try()); + test_mutex.Release(); +} + +TEST(LockPosixTest, TryLockNonRecursiveMutex_ExpectMutexNotLockedTwice) { + // Create Lock object (non-recursive mutex) + Lock test_mutex; + // Lock mutex + test_mutex.Try(); + // Try to lock it again. If locked expect false + EXPECT_FALSE(test_mutex.Try()); + test_mutex.Release(); +} + +TEST(LockPosixTest, TryLockRecursiveMutex_ExpectMutexLockedTwice) { + // Create Lock object (recursive mutex) + Lock test_mutex(true); + // Lock mutex + test_mutex.Try(); + // Try to lock it again. Expect true and internal counter increase + EXPECT_TRUE(test_mutex.Try()); + // Release mutex twice as was locked twice. + // Every Release() will decrement internal counter + test_mutex.Release(); + test_mutex.Release(); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/log4cxx.properties b/src/components/utils/test/log4cxx.properties new file mode 100644 index 0000000000..0ba34d0ad3 --- /dev/null +++ b/src/components/utils/test/log4cxx.properties @@ -0,0 +1,11 @@ +log4j.appender.AutoTraceTestLogFile=org.apache.log4j.FileAppender +log4j.appender.AutoTraceTestLogFile.File=AutoTraceTestLogFile.log +log4j.appender.AutoTraceTestLogFile.append=true +log4j.appender.AutoTraceTestLogFile.DatePattern='.' yyyy-MM-dd HH-mm +log4j.appender.AutoTraceTestLogFile.ImmediateFlush=true +log4j.appender.AutoTraceTestLogFile.layout=org.apache.log4j.PatternLayout +log4j.appender.AutoTraceTestLogFile.layout.ConversionPattern=%-5p [%d{dd MMM yyyy HH:mm:ss,SSS}][%c] %F:%L %M: %m%n + + +# All SmartDeviceLinkCore logs +log4j.rootLogger=ALL, AutoTraceTestLogFile
\ No newline at end of file diff --git a/src/components/utils/test/log_message_loop_thread_test.cc b/src/components/utils/test/log_message_loop_thread_test.cc new file mode 100644 index 0000000000..789bf62f45 --- /dev/null +++ b/src/components/utils/test/log_message_loop_thread_test.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "utils/log_message_loop_thread.h" +#include "utils/logger_status.h" + +namespace test { +namespace components { +namespace utils { + +using namespace ::logger; +using ::testing::_; + +TEST(LogMessageLoopThread,CreateLogMessageSingleton) { + //if logger_status is LoggerThreadNotCreated or LoggerThreadCreated, + // creation of singleton will be impossible + logger::logger_status = CreatingLoggerThread; + + LogMessageLoopThread *instance_1 = LogMessageLoopThread::instance(); + LogMessageLoopThread *instance_2 = LogMessageLoopThread::instance(); + + //assert + EXPECT_EQ(instance_1, instance_2); + + LogMessageLoopThread::destroy(); + + EXPECT_FALSE(LogMessageLoopThread::exists()); + logger::logger_status = LoggerThreadNotCreated; +} + +TEST(LogMessageLoopThread, DestroyLogMessage_loggerStatusDeletingLogger) { + logger::logger_status = CreatingLoggerThread; + LogMessageLoopThread::instance(); + + //assert + EXPECT_EQ(CreatingLoggerThread, logger::logger_status); + + //act + LogMessageLoopThread::destroy(); + + //assert + EXPECT_EQ(DeletingLoggerThread, logger::logger_status); + + logger::logger_status = LoggerThreadNotCreated; +} + +class MockLogMessageTest : public LogMessageHandler { + public: + MOCK_CONST_METHOD1(Handle, void(const LogMessage message)); +}; + +TEST(LogMessageLoopThread, HandleNeverCalled) { + logger::logger_status = CreatingLoggerThread; + + MockLogMessageTest mmock; + EXPECT_CALL(mmock,Handle(_)).Times(0); + LogMessageLoopThread::instance(); + + LogMessageLoopThread::destroy(); + logger::logger_status = LoggerThreadNotCreated; +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/message_queue_test.cc b/src/components/utils/test/message_queue_test.cc new file mode 100644 index 0000000000..fbae7a9e5e --- /dev/null +++ b/src/components/utils/test/message_queue_test.cc @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include "gtest/gtest.h" +#include "utils/message_queue.h" + +namespace test { +namespace components { +namespace utils { + +using ::utils::MessageQueue; + +class MessageQueueTest : public testing::Test { + public: + MessageQueueTest() + : test_val_1("Hello,"), + test_val_2("Beautiful "), + test_val_3("World!"), + test_line(""), + check_value(false) { + } + void add_one_element_to_queue(); + void extract_from_queue(); + void add_three_elements_to_queue(); + void ShutDownQueue(); + + static void* add_one_element_to_queue_helper(void *context); + static void* extract_from_queue_helper(void *context); + static void* add_three_elements_to_queue_helper(void *context); + static void* ShutDownQueue_helper(void *context); + + protected: + MessageQueue<std::string> test_queue; + std::string test_val_1; + std::string test_val_2; + std::string test_val_3; + std::string test_line; + bool check_value; +}; + +// Thread function - adds 1 element1 to the queue +void MessageQueueTest::add_one_element_to_queue() { + test_queue.push(test_val_1); + pthread_exit(NULL); +} + +// Thread function - removes 1 element from beginning of queue +void MessageQueueTest::extract_from_queue() { + test_queue.wait(); + test_line = test_queue.pop(); + pthread_exit(NULL); +} + +// Thread function - adds 3 elements to the queue +void MessageQueueTest::add_three_elements_to_queue() { + test_queue.push(test_val_1); + test_queue.push(test_val_2); + test_queue.push(test_val_3); + pthread_exit(NULL); +} + +// Thread function - adds 3 elements to the queue +void MessageQueueTest::ShutDownQueue() { + check_value = true; + test_queue.Shutdown(); + pthread_exit(NULL); +} + +void* MessageQueueTest::add_one_element_to_queue_helper(void *context) { + (reinterpret_cast<MessageQueueTest *>(context))->add_one_element_to_queue(); + return NULL; +} +void* MessageQueueTest::extract_from_queue_helper(void *context) { + (reinterpret_cast<MessageQueueTest *>(context))->extract_from_queue(); + return NULL; +} +void* MessageQueueTest::add_three_elements_to_queue_helper(void *context) { + (reinterpret_cast<MessageQueueTest *>(context))->add_three_elements_to_queue(); + return NULL; +} +void* MessageQueueTest::ShutDownQueue_helper(void *context) { + (reinterpret_cast<MessageQueueTest *>(context))->ShutDownQueue(); + return NULL; +} + +TEST_F(MessageQueueTest, DefaultCtorTest_ExpectEmptyQueueCreated) { + bool test_value = true; + // Check if the queue is empty + ASSERT_EQ(test_value, test_queue.empty()); +} + +TEST_F(MessageQueueTest, MessageQueuePushThreeElementsTest_ExpectThreeElementsAdded) { + pthread_t thread1; + pthread_create(&thread1, NULL, &MessageQueueTest::add_three_elements_to_queue_helper, this); + pthread_join(thread1, NULL); + // check if 3 elements were added successfully + ASSERT_EQ(3u, test_queue.size()); +} + +TEST_F(MessageQueueTest, NotEmptyMessageQueueResetTest_ExpectEmptyQueue) { + // Adding some elements to queue + test_queue.push(test_val_1); + test_queue.push(test_val_2); + test_queue.push(test_val_3); + // Resetting queue + test_queue.Reset(); + // Check if queue is empty + ASSERT_TRUE(test_queue.empty()); + // Check the size of queue after reset + ASSERT_EQ(0u, test_queue.size()); +} + +TEST_F(MessageQueueTest, MessageQueuePopOneElementTest_ExpectOneElementRemovedFromQueue) { + pthread_t thread1; + pthread_t thread2; + // Creating threads with thread function mentioned above + pthread_create(&thread1, NULL, &MessageQueueTest::add_one_element_to_queue_helper, this); + pthread_create(&thread2, NULL, &MessageQueueTest::extract_from_queue_helper, this); + // Primary thread waits until thread 2 to be finished + pthread_join(thread2, NULL); + // Check if first element was removed successfully + ASSERT_EQ(test_val_1, test_line); + // Check the size of queue after 1 element was removed + ASSERT_EQ(0u, test_queue.size()); +} + +TEST_F(MessageQueueTest, MessageQueueShutdownTest_ExpectMessageQueueWillBeShutDown) { + pthread_t thread1; + // Creating thread with thread function mentioned above + pthread_create(&thread1, NULL, &MessageQueueTest::ShutDownQueue_helper, this); + // Primary thread sleeps until thread1 will make queue shutdown + test_queue.wait(); + check_value = true; + ASSERT_TRUE(check_value); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/messagemeter_test.cc b/src/components/utils/test/messagemeter_test.cc index 45375e4ed6..6c13ab345e 100644 --- a/src/components/utils/test/messagemeter_test.cc +++ b/src/components/utils/test/messagemeter_test.cc @@ -79,7 +79,7 @@ class MessageMeterTest: public ::testing::TestWithParam<TimePair> { void TearDown() OVERRIDE { } ::utils::MessageMeter<int> meter; - TimevalStruct time_range {0, 0}; + TimevalStruct time_range = {0, 0}; int64_t time_range_msecs; int usecs; int id1, id2, id3; diff --git a/src/components/utils/test/posix_thread_test.cc b/src/components/utils/test/posix_thread_test.cc new file mode 100644 index 0000000000..d597f036d0 --- /dev/null +++ b/src/components/utils/test/posix_thread_test.cc @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/lock.h" +#include "threads/thread.h" + +namespace test { +namespace components { +namespace utils { + +using namespace sync_primitives; +using namespace threads; + +// TODO(AByzhynar): Change this to use Gtest class to create all variables for every TEST_F +// TODO(AByzhynar): Add multithreading tests + +namespace { +const uint32_t MAX_SIZE = 20; +const size_t MyStackSize = 32768; +const char *threadName("test thread"); +const std::string test_thread_name("THREAD"); +sync_primitives::ConditionalVariable cond_var_; +sync_primitives::Lock test_mutex_; +}; + +// ThreadDelegate successor +class TestThreadDelegate : public threads::ThreadDelegate { + public: + TestThreadDelegate() + : check_value_(false) { + } + void threadMain() { + AutoLock test_lock(test_mutex_); + check_value_ = true; + cond_var_.NotifyOne(); + } + + bool check_value() const { + return check_value_; + } + private: + bool check_value_; +}; + +TEST(PosixThreadTest, CreateThread_ExpectThreadCreated) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + EXPECT_TRUE(thread != NULL); + EXPECT_EQ(thread, threadDelegate->thread()); + EXPECT_EQ(thread->delegate(), threadDelegate); + DeleteThread(thread); + delete threadDelegate; + // Check Delegate Dtor worked successfully + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, CheckCreatedThreadName_ExpectCorrectName) { + // Arrange + threads::Thread *thread = NULL; + threads::ThreadDelegate *threadDelegate = new TestThreadDelegate(); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Check thread was created with correct name + EXPECT_EQ(threadName, thread->name()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, CheckCreatedThreadNameChangeToLongName_ExpectThreadNameReduced) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize)); + // Rename started thread. Name will be cut to 15 symbols + '\0' + // This is the limit in current POSIX thread implementation + thread->SetNameForId(thread->thread_handle(), + std::string("new thread with changed name")); + // Name must be large enough to keep 16 symbols. Read previous comment + char name[MAX_SIZE]; + int result = pthread_getname_np(thread->thread_handle(), name, sizeof(name)); + if (!result) + EXPECT_EQ(std::string("new thread with"), std::string(name)); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartCreatedThreadWithOptionsJoinableAndMyStackSize_ExpectMyStackSizeStackAndJoinableThreadStarted) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start thread with following options (Stack size = 32768 & thread is joinable) + thread->start(threads::ThreadOptions(MyStackSize)); + // Check thread is joinable + EXPECT_TRUE(thread->is_joinable()); + // Check thread stack size is 32768 + EXPECT_EQ(MyStackSize, thread->stack_size()); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartCreatedThreadWithDefaultOptions_ExpectZeroStackAndJoinableThreadStarted) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start thread with default options (Stack size = 0 & thread is joinable) + thread->start(threads::ThreadOptions()); + // Check thread is joinable + EXPECT_TRUE(thread->is_joinable()); + // Check thread stack size is minimum value. Stack can not be 0 + EXPECT_EQ(Thread::kMinStackSize, thread->stack_size()); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartThreadWithZeroStackAndDetached_ExpectMinimumStackAndDetachedThreadStarted) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start thread with default options (Stack size = 0 & thread is detached) + thread->start(threads::ThreadOptions(0, false)); + // Check thread is detached + EXPECT_FALSE(thread->is_joinable()); + // Check thread stack size is 0 + EXPECT_EQ(Thread::kMinStackSize, thread->stack_size()); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, DISABLED_CheckCreatedThreadNameChangeToEmpty_ExpectThreadNameChangedToEmpty) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize)); + // Rename started thread. Name will be cut to 15 symbols + '\0' + // This is the limit in current POSIX thread implementation + thread->SetNameForId(thread->thread_handle(), std::string("")); + // Name must be large enough to keep 16 symbols. Read previous comment + char name[MAX_SIZE]; + int result = pthread_getname_np(thread->thread_handle(), name, sizeof(name)); + if (!result) { + EXPECT_EQ(std::string(""), std::string(name)); + } + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, CheckCreatedThreadNameChangeToShortName_ExpectThreadNameChangedToShort) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start created thread + thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize)); + // Rename started thread. Name will be cut to 15 symbols + '\0' + // This is the limit in current POSIX thread implementation + thread->SetNameForId(thread->thread_handle(), test_thread_name); + // Name must be large enough to keep 16 symbols. Read previous comment + char name[MAX_SIZE]; + int result = pthread_getname_np(thread->thread_handle(), name, sizeof(name)); + if (!result) { + EXPECT_EQ(test_thread_name, std::string(name)); + } + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartThread_ExpectThreadStarted) { + // Arrange + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start created thread + EXPECT_TRUE(thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize))); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartOneThreadTwice_ExpectTheSameThreadStartedTwice) { + // Arrange + PlatformThreadHandle thread1_id; + PlatformThreadHandle thread2_id; + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start created thread + EXPECT_TRUE(thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize))); + thread1_id = thread->CurrentId(); + thread->stop(); + // Try to start thread again + EXPECT_TRUE(thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize))); + thread2_id = thread->CurrentId(); + EXPECT_EQ(thread1_id, thread2_id); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +TEST(PosixThreadTest, StartOneThreadAgainAfterRename_ExpectRenamedThreadStarted) { + // Arrange + PlatformThreadHandle thread1_id; + PlatformThreadHandle thread2_id; + threads::Thread *thread = NULL; + TestThreadDelegate *threadDelegate = new TestThreadDelegate(); + AutoLock test_lock(test_mutex_); + // Create thread + ASSERT_NO_THROW(thread = CreateThread(threadName, threadDelegate)); + // Start created thread + EXPECT_TRUE(thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize))); + thread1_id = thread->CurrentId(); + // Rename started thread. Name will be cut to 15 symbols + '\0' + // This is the limit in current POSIX thread implementation + thread->SetNameForId(thread->thread_handle(), test_thread_name); + // Name must be large enough to keep 16 symbols. Read previous comment + char name[MAX_SIZE]; + int result = pthread_getname_np(thread->thread_handle(), name, sizeof(name)); + if (!result) + EXPECT_EQ(test_thread_name, std::string(name)); + // Stop thread + thread->stop(); + EXPECT_TRUE(thread->start(threads::ThreadOptions(threads::Thread::kMinStackSize))); + thread2_id = thread->CurrentId(); + // Expect the same thread started with the the same name + EXPECT_EQ(test_thread_name, std::string(name)); + EXPECT_EQ(thread1_id, thread2_id); + cond_var_.WaitFor(test_lock, 10000); + EXPECT_TRUE(threadDelegate->check_value()); + DeleteThread(thread); + delete threadDelegate; + EXPECT_EQ(NULL, thread->delegate()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/resource_usage_test.cc b/src/components/utils/test/resource_usage_test.cc new file mode 100644 index 0000000000..c10bbea865 --- /dev/null +++ b/src/components/utils/test/resource_usage_test.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include "gtest/gtest.h" +#include "utils/macro.h" + +#include "utils/resource_usage.h" +#include "utils/file_system.h" + +namespace utils { + +class ResourceUsagePrivateTest : public ::testing::Test { + protected: + Resources res; +}; + +TEST_F(ResourceUsagePrivateTest, ReadStatFileTest) { + std::string proc_buf; + EXPECT_TRUE(res.ReadStatFile(proc_buf)); +} + +TEST_F(ResourceUsagePrivateTest, GetProcInfoTest) { + Resources::PidStats pid_stat; + EXPECT_TRUE(res.GetProcInfo(pid_stat)); +} + +TEST_F(ResourceUsagePrivateTest, GetMemInfoTest) { + Resources::MemInfo mem_info; + EXPECT_TRUE(res.GetMemInfo(mem_info)); +} + +TEST_F(ResourceUsagePrivateTest, GetStatPathTest_FileExists) { + //arrange + std::string filename = res.GetStatPath(); + //assert + EXPECT_TRUE(file_system::FileExists(filename)); +} + +TEST_F(ResourceUsagePrivateTest, GetStatPathTest_ReadFile) { + //arrange + std::string filename = res.GetStatPath(); + std::string output; + //assert + EXPECT_TRUE(file_system::ReadFile(filename, output)); + +} +TEST_F(ResourceUsagePrivateTest, GetProcPathTest) { + ///arrange + std::string fd = res.GetProcPath(); + std::string filename = res.GetStatPath(); + //assert + EXPECT_EQ(filename, fd + "/stat"); +} +} + +namespace test { +namespace components { +namespace utils { +using namespace ::utils; + +TEST(ResourceUsageTest, SuccesfulGrabResources) { + ResourseUsage* resources = Resources::getCurrentResourseUsage(); + EXPECT_TRUE(resources != NULL); + delete resources; + +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/rwlock_posix_test.cc b/src/components/utils/test/rwlock_posix_test.cc new file mode 100644 index 0000000000..779b57ff32 --- /dev/null +++ b/src/components/utils/test/rwlock_posix_test.cc @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/rwlock.h" + +namespace test { +namespace components { +namespace utils { + +using sync_primitives::RWLock; + +class RWlockTest : public ::testing::Test { + public: + void ThreadsDispatcher(void* (*func)(void*)) { + for (uint8_t i = 0; i < kNum_threads_; ++i) { + bool thread_created = (pthread_create(&thread[i], NULL, func, this) == 0); + ASSERT_TRUE(thread_created); + } + for (uint8_t i = 0; i < kNum_threads_; ++i) { + pthread_join(thread[i], NULL); + } + } + + void ReadLock() { + EXPECT_TRUE(test_rwlock.AcquireForReading()); + EXPECT_TRUE(test_rwlock.Release()); + } + + void ExpectReadLockFail() { + bool temp = test_rwlock.TryAcquireForReading(); + EXPECT_FALSE(temp); + if (temp) { + test_rwlock.Release(); + } + } + + void ExpectWriteLockFail() { + bool temp = test_rwlock.TryAcquireForWriting(); + EXPECT_FALSE(temp); + if (temp) { + test_rwlock.Release(); + } + } + + static void* ReadLock_helper(void *context) { + RWlockTest *temp = reinterpret_cast<RWlockTest *>(context); + temp->ReadLock(); + return NULL; + } + + static void* TryReadLock_helper(void *context) { + RWlockTest *temp = reinterpret_cast<RWlockTest *>(context); + temp->ExpectReadLockFail(); + return NULL; + } + + static void* TryWriteLock_helper(void *context) { + RWlockTest *temp = reinterpret_cast<RWlockTest *>(context); + temp->ExpectWriteLockFail(); + return NULL; + } + + protected: + RWLock test_rwlock; + enum { kNum_threads_ = 5 }; + pthread_t thread[kNum_threads_]; +}; + +TEST_F(RWlockTest, AcquireForReading_ExpectAccessForReading) { + // Lock rw lock for reading + EXPECT_TRUE(test_rwlock.AcquireForReading()); + // Try to lock rw lock for reading again + EXPECT_TRUE(test_rwlock.AcquireForReading()); + // Creating kNumThreads threads, starting them with callback function, waits until all of them finished + ThreadsDispatcher(&RWlockTest::ReadLock_helper); + // Releasing RW locks + EXPECT_TRUE(test_rwlock.Release()); + EXPECT_TRUE(test_rwlock.Release()); +} + +TEST_F(RWlockTest, AcquireForReading_ExpectNoAccessForWriting) { + // Lock rw lock for reading + EXPECT_TRUE(test_rwlock.AcquireForReading()); + // Try to lock rw lock for writing + EXPECT_FALSE(test_rwlock.TryAcquireForWriting()); + // Creating kNumThreads threads, starting them with callback function, waits until all of them finished + ThreadsDispatcher(&RWlockTest::TryWriteLock_helper); + EXPECT_TRUE(test_rwlock.Release()); +} + +TEST_F(RWlockTest, AcquireForWriting_ExpectNoAccessForReading) { + // Lock rw lock for writing + EXPECT_TRUE(test_rwlock.AcquireForWriting()); + // Try to lock rw lock for reading + EXPECT_FALSE(test_rwlock.TryAcquireForReading()); + // Creating kNumThreads threads, starting them with callback function, waits until all of them finished + ThreadsDispatcher(&RWlockTest::TryReadLock_helper); + EXPECT_TRUE(test_rwlock.Release()); +} + +TEST_F(RWlockTest, AcquireForWriting_ExpectNoMoreAccessForWriting) { + // Lock rw lock for writing + EXPECT_TRUE(test_rwlock.AcquireForWriting()); + // Try to lock rw lock for reading + EXPECT_FALSE(test_rwlock.TryAcquireForWriting()); + // Creating kNumThreads threads, starting them with callback function, waits until all of them finished + ThreadsDispatcher(&RWlockTest::TryWriteLock_helper); + EXPECT_TRUE(test_rwlock.Release()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/signals_linux_test.cc b/src/components/utils/test/signals_linux_test.cc new file mode 100644 index 0000000000..263f240ec8 --- /dev/null +++ b/src/components/utils/test/signals_linux_test.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include <assert.h> +#include "gtest/gtest.h" +#include "utils/signals.h" + +namespace test { +namespace components { +namespace utils { + +void handler(int sig) { +} + +TEST(SignalsLinuxTest, SubscribeToTerminateSignal_Positive) { + ASSERT_TRUE(::utils::SubscribeToTerminateSignal(handler)); +} + +TEST(SignalsLinuxTest, SubscribeToFaultSignal_Positive) { + ASSERT_TRUE(::utils::SubscribeToFaultSignal(handler)); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/singleton_test.cc b/src/components/utils/test/singleton_test.cc new file mode 100644 index 0000000000..8a9e6b31e1 --- /dev/null +++ b/src/components/utils/test/singleton_test.cc @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/singleton.h" +#include <pthread.h> + +namespace test { +namespace components { +namespace utils { + +using ::utils::Singleton; + +class SingletonTest : public ::utils::Singleton<SingletonTest> { + public: + + void SetValue(int value) { + test_value = value; + } + int GetValue() { + return test_value; + } + + FRIEND_BASE_SINGLETON_CLASS (SingletonTest); + private: + int test_value; +}; + +TEST(SingletonTest, CreateAndDestroySingleton) { + //assert + ASSERT_EQ(SingletonTest::instance(), SingletonTest::instance()); + ASSERT_EQ(0, SingletonTest::instance()->GetValue()); + ASSERT_TRUE(SingletonTest::exists()); + SingletonTest::instance()->SetValue(5); + ASSERT_EQ(5, SingletonTest::instance()->GetValue()); + + //act + SingletonTest::destroy(); + + //assert + ASSERT_FALSE(SingletonTest::exists()); +} + +TEST(SingletonTest, DestroySingletonTwice) { + //assert + ASSERT_EQ(0, SingletonTest::instance()->GetValue()); + ASSERT_TRUE(SingletonTest::exists()); + + //act + SingletonTest::destroy(); + //assert + ASSERT_FALSE(SingletonTest::exists()); + + //act + SingletonTest::destroy(); + //assert + ASSERT_FALSE(SingletonTest::exists()); +} + +TEST(SingletonTest, DeleteSingletonCreateAnother) { + //arrange + SingletonTest::instance()->SetValue(10); + //assert + ASSERT_TRUE(SingletonTest::exists()); + ASSERT_EQ(10, SingletonTest::instance()->GetValue()); + //act + SingletonTest::destroy(); + //assert + ASSERT_FALSE(SingletonTest::exists()); + + //act + SingletonTest::instance(); + + //assert + ASSERT_EQ(0, SingletonTest::instance()->GetValue()); + ASSERT_TRUE(SingletonTest::exists()); + SingletonTest::destroy(); +} + +void* func_pthread1(void*) { + SingletonTest* singleton_in_other_thread = SingletonTest::instance(); + pthread_exit(singleton_in_other_thread); + return NULL; +} + +void* func_pthread2(void * value) { + SingletonTest * instance = reinterpret_cast<SingletonTest *>(value); + instance->destroy(); + pthread_exit (NULL); + return NULL; +} + +TEST(SingletonTest, CreateSingletonInDifferentThreads) { + //arrange + SingletonTest::instance(); + ASSERT_TRUE(SingletonTest::exists()); + + pthread_t thread1; + pthread_create(&thread1, NULL, func_pthread1, NULL); + + void *instance2; + pthread_join(thread1, &instance2); + SingletonTest * instance_2 = reinterpret_cast<SingletonTest *>(instance2); + + //assert + ASSERT_EQ(SingletonTest::instance(), instance_2); + + //act + SingletonTest::destroy(); + //assert + ASSERT_FALSE(SingletonTest::exists()); +} + +TEST(SingletonTest, CreateDeleteSingletonInDifferentThreads) { + //arrange + pthread_t thread1; + pthread_create(&thread1, NULL, func_pthread1, NULL); + + pthread_t thread2; + pthread_create(&thread2, NULL, func_pthread1, NULL); + + void *instance1; + pthread_join(thread1, &instance1); + SingletonTest * instance_1 = reinterpret_cast<SingletonTest *>(instance1); + + void *instance2; + pthread_join(thread2, &instance2); + SingletonTest * instance_2 = reinterpret_cast<SingletonTest *>(instance2); + + //assert + ASSERT_TRUE(instance_1->exists()); + ASSERT_TRUE(instance_2->exists()); + + ASSERT_EQ(instance_1, instance_2); + + //act + SingletonTest::destroy(); + + //assert + ASSERT_FALSE(instance_1->exists()); + ASSERT_FALSE(instance_2->exists()); +} + +TEST(SingletonTest, DeleteSingletonInDifferentThread) { + //arrange + SingletonTest::instance(); + ASSERT_TRUE(SingletonTest::exists()); + + pthread_t thread1; + pthread_create(&thread1, NULL, func_pthread2, SingletonTest::instance()); + + pthread_join(thread1, NULL); + + //assert + ASSERT_FALSE(SingletonTest::exists()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/stl_utils_test.cc b/src/components/utils/test/stl_utils_test.cc new file mode 100644 index 0000000000..62c6d9404b --- /dev/null +++ b/src/components/utils/test/stl_utils_test.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "utils/stl_utils.h" + +namespace test { +namespace components { +namespace utils { + +using ::utils::StlCollectionDeleter; +using ::utils::StlMapDeleter; + +class TestObject { + public: + ~TestObject() { + } +}; + +typedef std::map<int, TestObject*> TestMap; +typedef std::vector<TestObject*> TestVector; + +TEST(StlDeleter, DestructMapWithOneElement) { + TestMap test_map; + test_map[1] = new TestObject(); + + EXPECT_EQ(1, test_map.size()); + { + StlMapDeleter<TestMap> test_list_deleter_(&test_map); + } + EXPECT_EQ(1, test_map.size()); + EXPECT_EQ(NULL, test_map[1]); +} + +TEST(StlDeleter, DestructMapWithSeveralElements) { + TestMap test_map; + test_map[1] = new TestObject(); + test_map[2] = new TestObject(); + + EXPECT_EQ(2, test_map.size()); + { + StlMapDeleter<TestMap> test_list_deleter_(&test_map); + } + EXPECT_EQ(2, test_map.size()); + EXPECT_EQ(NULL, test_map[1]); + EXPECT_EQ(NULL, test_map[2]); +} + +TEST(StlDeleter, DestructVectorWithOneElement) { + TestVector test_vector; + test_vector.push_back(new TestObject()); + + EXPECT_EQ(1, test_vector.size()); + { + StlCollectionDeleter<TestVector> test_list_deleter_(&test_vector); + } + EXPECT_EQ(1, test_vector.size()); + EXPECT_EQ(NULL, test_vector[0]); +} + +TEST(StlDeleter, DestructVectorWithSeveralElements) { + TestVector test_vector; + test_vector.push_back(new TestObject()); + test_vector.push_back(new TestObject()); + + EXPECT_EQ(2, test_vector.size()); + { + StlCollectionDeleter<TestVector> test_list_deleter_(&test_vector); + } + EXPECT_EQ(2, test_vector.size()); + EXPECT_EQ(NULL, test_vector[0]); + EXPECT_EQ(NULL, test_vector[1]); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/system_test.cc b/src/components/utils/test/system_test.cc new file mode 100644 index 0000000000..42307998b4 --- /dev/null +++ b/src/components/utils/test/system_test.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gmock/gmock.h" +#include "utils/system.h" + +namespace test { +namespace components { +namespace utils { + +using namespace ::utils; + +TEST(SystemTest, Constructor_WithCommandName_ExpectArgsStored) { + // Command creation without any arguments + const std::string test_command("ls"); + System object(test_command); + + // Check if the object was created with correct command + ASSERT_EQ(object.command(), test_command); + int vec_size = object.argv().size(); + ASSERT_EQ(vec_size, 1); +} + +TEST(SystemTest, Constructor_WithFileNameCommandName_ExpectArgsStored) { + // Command creation with 1 argument + const std::string test_command("ls"); + const std::string test_list_args("-la"); + System object(test_command, test_list_args); + + // Check if the object was created with correct command + ASSERT_EQ(object.command(), test_command); + + // Check if actual number of arguments arec correct + int vec_size = object.argv().size(); + ASSERT_EQ(vec_size, 1); // Correct number of arguments is 1 + +} + +TEST(SystemTest, AddTwoArgsToCommand_ExpectTwoArgsAdded) { + const std::string test_command("echo"); + const char* args[] = {"-e", "\b"}; + System object(test_command); + + // Adding arguments + object.Add(args[0]); + object.Add(args[1]); + + // Check if actual number of arguments equal args stored in object + int vec_size = object.argv().size(); + ASSERT_EQ(vec_size, 3); // Correct number of arguments is 3 +} + +TEST(SystemTest, AddTwoArgsToCommand_CheckOrder_ExpectOrderCorrect) { + const std::string test_command("echo"); + const char* args[] = {"-e", "\b"}; + System object(test_command); + + // Adding arguments + object.Add(args[0]); + object.Add(args[1]); + + // Check if the object was appended by correct arguments in correct order + EXPECT_STREQ(object.argv()[1].c_str(), args[0]); + EXPECT_STREQ(object.argv()[2].c_str(), args[1]); +} + + + +TEST(SystemTest, SynchronousInvokeWithExistingCommand_ExpectSuccessfull) { + const std::string test_command("./testscript.sh"); + System object(test_command); + + // Check if Execute() method is working properly with synchronous command invoke + ASSERT_TRUE(object.Execute(true)); +} + +TEST(SystemTest, SynchronousInvokeWithEmptyCommand_IncorrectCommand_ExpectFailed) { + const std::string test_command(""); // any incorrect command + System object(test_command); + + // Check if Execute() method will fail with not correct command (synchronous command invoke) + ASSERT_FALSE(object.Execute(true)); +} + +TEST(SystemTest, ASynchronousInvokeEmptyCommand_InvokeSuccessfull) { + const std::string test_command(""); // Possible to put here any command (existing or incorrect) + const std::string test_list_args("anything"); // as command will never be executed from child process + System object(test_command, test_list_args); // as parrent process does not wait for child process to be finished + + // Check if Execute() method is working properly with asynchronous command invoke + ASSERT_TRUE(object.Execute()); +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/testscript.sh b/src/components/utils/test/testscript.sh new file mode 100755 index 0000000000..c42d8e78b0 --- /dev/null +++ b/src/components/utils/test/testscript.sh @@ -0,0 +1,5 @@ +#!/bin/sh +echo "Hello, Ford " + + + diff --git a/src/components/utils/test/thread_validator_test.cc b/src/components/utils/test/thread_validator_test.cc new file mode 100644 index 0000000000..16d9d12874 --- /dev/null +++ b/src/components/utils/test/thread_validator_test.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> + +#include "gtest/gtest.h" + +#include "utils/threads/thread_validator.h" + +namespace test { +namespace components { +namespace utils { + +using namespace ::threads; + +TEST(ThreadValidatorTest, CompareID_CurrentThreadAndPthread_AreEqual) { + SingleThreadSimpleValidator object; + ASSERT_EQ(object.creation_thread_id(), pthread_self()); + +} + +} // namespace utils +} // namespace components +} // namespace test diff --git a/src/components/utils/test/timer_thread_test.cc b/src/components/utils/test/timer_thread_test.cc new file mode 100644 index 0000000000..be25e03b7b --- /dev/null +++ b/src/components/utils/test/timer_thread_test.cc @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <pthread.h> +#include <iostream> + +#include "lock.h" +#include "macro.h" + +#include "gtest/gtest.h" +#include "utils/conditional_variable.h" +#include "utils/timer_thread.h" + +namespace test { +namespace components { +namespace utils { + +using namespace timer; +using namespace sync_primitives; + +class TimerThreadTest : public ::testing::Test { + public: + TimerThreadTest() + : check_val(0), + val1(3), + val2(4), + wait_val(3000) { + } + + void function() { + AutoLock alock(lock_); + ++check_val; + condvar_.NotifyOne(); + } + + protected: + uint32_t check_val; + Lock lock_; + ConditionalVariable condvar_; + const uint32_t val1; + const uint32_t val2; + const uint32_t wait_val; +}; + +TEST_F(TimerThreadTest, StartTimerThreadWithTimeoutOneSec_ExpectSuccessfullInvokeCallbackFuncOnTimeout) { + // Create Timer with TimerDeleagate + TimerThread<TimerThreadTest> timer("Test", this, &TimerThreadTest::function, + false); + AutoLock alock(lock_); + EXPECT_EQ(0, check_val); + // Start timer with 1 second timeout + timer.start(1); + condvar_.WaitFor(alock, wait_val); + EXPECT_EQ(1, check_val); +} + +TEST_F(TimerThreadTest, StartTimerThreadWithTimeoutOneSecInLoop_ExpectSuccessfullInvokeCallbackFuncOnEveryTimeout) { + // Create Timer with TimerLooperDeleagate + TimerThread<TimerThreadTest> timer("Test", this, &TimerThreadTest::function, + true); + AutoLock alock(lock_); + EXPECT_EQ(0, check_val); + // Start timer with 1 second timeout + timer.start(1); + while (check_val < val2) { + condvar_.WaitFor(alock, wait_val); + } + // Check callback function was called 4 times + EXPECT_EQ(val2, check_val); +} + +TEST_F(TimerThreadTest, StopStartedTimerThreadWithTimeoutOneSecInLoop_ExpectSuccessfullStop) { + // Create Timer with TimerLooperDeleagate + TimerThread<TimerThreadTest> timer("Test", this, &TimerThreadTest::function, + true); + AutoLock alock(lock_); + EXPECT_EQ(0, check_val); + // Start timer with 1 second timeout + timer.start(1); + // Stop timer on 3rd second + while (check_val < val2) { + if (check_val == val1) { + timer.stop(); + break; + } + condvar_.WaitFor(alock, wait_val); + } + EXPECT_EQ(val1, check_val); +} + +TEST_F(TimerThreadTest, ChangeTimeoutForStartedTimerThreadWithTimeoutOneSecInLoop_ExpectSuccessfullStop) { + // Create Timer with TimerLooperDeleagate + TimerThread<TimerThreadTest> timer("Test", this, &TimerThreadTest::function, + true); + AutoLock alock(lock_); + EXPECT_EQ(0, check_val); + // Start timer with 1 second timeout + timer.start(1); + // Change timer timeout on 3rd second + while (check_val < val2) { + if (check_val == val1) { + timer.updateTimeOut(2); + } + condvar_.WaitFor(alock, wait_val); + } + EXPECT_EQ(val2, check_val); +} + +TEST_F(TimerThreadTest, CheckStartedTimerIsRunning_ExpectTrue) { + // Create Timer with TimerLooperDeleagate + TimerThread<TimerThreadTest> timer("Test", this, &TimerThreadTest::function, + true); + AutoLock alock(lock_); + EXPECT_EQ(0, check_val); + // Start timer with 1 second timeout + timer.start(1); + // Change timer timeout on 3rd second + while (check_val < val1) { + condvar_.WaitFor(alock, wait_val); + // Check start is running + EXPECT_TRUE(timer.isRunning()); + } + EXPECT_EQ(val1, check_val); +} + +} // namespace utils +} // namespace components +} // namespace test + |