This is an automated email from the ASF dual-hosted git repository. fgerlits pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit 58a3041fa0efc635b5f6a8fedafda55f3448e676 Author: Martin Zink <[email protected]> AuthorDate: Thu May 19 09:37:42 2022 +0200 MINIFICPP-1842 getTimeStr should use std::chrono Also fixes MINIFICPP-1700 Change leftover integers to std::chrono in ListSFTP. Signed-off-by: Ferenc Gerlits <[email protected]> This closes #1352 --- extensions/sftp/processors/ListSFTP.cpp | 85 ++++++------ extensions/sftp/processors/ListSFTP.h | 6 +- extensions/sftp/processors/PutSFTP.cpp | 19 ++- extensions/sftp/tests/ListSFTPTests.cpp | 3 +- .../processors/LogAttribute.cpp | 4 +- libminifi/include/core/Property.h | 10 -- libminifi/include/utils/TimeUtil.h | 144 +++++---------------- libminifi/include/utils/tls/CertificateUtils.h | 14 +- libminifi/src/controllers/SSLContextService.cpp | 4 +- libminifi/src/utils/tls/CertificateUtils.cpp | 16 +-- libminifi/test/unit/PropertyTests.cpp | 33 +---- libminifi/test/unit/TimeUtilTests.cpp | 133 ++++++++++--------- 12 files changed, 167 insertions(+), 304 deletions(-) diff --git a/extensions/sftp/processors/ListSFTP.cpp b/extensions/sftp/processors/ListSFTP.cpp index 573eeb50f..83b67b2bd 100644 --- a/extensions/sftp/processors/ListSFTP.cpp +++ b/extensions/sftp/processors/ListSFTP.cpp @@ -63,6 +63,21 @@ constexpr char const* ListSFTP::TARGET_SYSTEM_TIMESTAMP_PRECISION_MINUTES; constexpr char const* ListSFTP::ENTITY_TRACKING_INITIAL_LISTING_TARGET_TRACKING_TIME_WINDOW; constexpr char const* ListSFTP::ENTITY_TRACKING_INITIAL_LISTING_TARGET_ALL_AVAILABLE; +namespace { +uint64_t toUnixTime(const std::optional<std::chrono::system_clock::time_point> time_point) { + if (!time_point) + return 0; + return std::chrono::duration_cast<std::chrono::milliseconds>(time_point->time_since_epoch()).count(); +} + +std::optional<std::chrono::system_clock::time_point> fromUnixTime(const uint64_t timestamp) { + if (timestamp == 0) + return std::nullopt; + return std::chrono::system_clock::time_point{std::chrono::milliseconds{timestamp}}; +} + +} // namespace + void ListSFTP::initialize() { logger_->log_trace("Initializing FetchSFTP"); @@ -82,8 +97,6 @@ ListSFTP::ListSFTP(const std::string& name, const utils::Identifier& uuid /*= ut , minimum_file_size_(0U) , maximum_file_size_(0U) , already_loaded_from_cache_(false) - , last_listed_latest_entry_timestamp_(0U) - , last_processed_latest_entry_timestamp_(0U) , initial_listing_complete_(false) { logger_ = core::logging::LoggerFactory<ListSFTP>::getLogger(); } @@ -174,8 +187,8 @@ void ListSFTP::invalidateCache() { already_loaded_from_cache_ = false; last_run_time_ = std::chrono::steady_clock::time_point(); - last_listed_latest_entry_timestamp_ = 0U; - last_processed_latest_entry_timestamp_ = 0U; + last_listed_latest_entry_timestamp_.reset(); + last_processed_latest_entry_timestamp_.reset(); latest_identifiers_processed_.clear(); initial_listing_complete_ = false; @@ -323,11 +336,7 @@ bool ListSFTP::createAndTransferFlowFileFromChild( logger_->log_error("Modification date %lu of \"%s/%s\" larger than int64_t max", child.attrs.mtime, child.parent_path.c_str(), child.filename.c_str()); return true; } - std::string mtime_str; - if (!utils::timeutils::getDateTimeStr(gsl::narrow<int64_t>(child.attrs.mtime), mtime_str)) { - logger_->log_error("Failed to convert modification date %lu of \"%s/%s\" to string", child.attrs.mtime, child.parent_path.c_str(), child.filename.c_str()); - return true; - } + auto mtime_str = utils::timeutils::getDateTimeStr(date::sys_seconds{std::chrono::seconds(child.attrs.mtime)}); /* Create FlowFile */ auto flow_file = session->create(); @@ -380,8 +389,8 @@ bool ListSFTP::persistTrackingTimestampsCache(const std::shared_ptr<core::Proces state["hostname"] = hostname; state["username"] = username; state["remote_path"] = remote_path; - state["listing.timestamp"] = std::to_string(last_listed_latest_entry_timestamp_); - state["processed.timestamp"] = std::to_string(last_processed_latest_entry_timestamp_); + state["listing.timestamp"] = std::to_string(toUnixTime(last_listed_latest_entry_timestamp_)); + state["processed.timestamp"] = std::to_string(toUnixTime(last_processed_latest_entry_timestamp_)); size_t i = 0; for (const auto& identifier : latest_identifiers_processed_) { state["id." + std::to_string(i)] = identifier; @@ -464,8 +473,8 @@ bool ListSFTP::updateFromTrackingTimestampsCache(const std::shared_ptr<core::Pro return false; } - last_listed_latest_entry_timestamp_ = state_listing_timestamp; - last_processed_latest_entry_timestamp_ = state_processed_timestamp; + last_listed_latest_entry_timestamp_ = fromUnixTime(state_listing_timestamp); + last_processed_latest_entry_timestamp_ = fromUnixTime(state_processed_timestamp); latest_identifiers_processed_ = std::move(state_ids); return true; @@ -479,7 +488,7 @@ void ListSFTP::listByTrackingTimestamps( const std::string& username, const std::string& remote_path, std::vector<Child>&& files) { - uint64_t min_timestamp_to_list = last_listed_latest_entry_timestamp_; + auto min_timestamp_to_list = last_listed_latest_entry_timestamp_; /* Load state from cache file if needed */ if (!already_loaded_from_cache_) { @@ -492,16 +501,16 @@ void ListSFTP::listByTrackingTimestamps( } std::chrono::steady_clock::time_point current_run_time = std::chrono::steady_clock::now(); - time_t now = time(nullptr); + auto now = std::chrono::system_clock::now(); /* Order children by timestamp and try to detect timestamp precision if needed */ - std::map<uint64_t /*timestamp*/, std::list<Child>> ordered_files; + std::map<std::chrono::system_clock::time_point, std::list<Child>> ordered_files; bool target_system_has_seconds = false; for (auto&& file : files) { - uint64_t timestamp = file.attrs.mtime * 1000; - target_system_has_seconds |= timestamp % 60000 != 0; + std::chrono::system_clock::time_point timestamp{std::chrono::seconds(file.attrs.mtime)}; + target_system_has_seconds |= std::chrono::round<std::chrono::minutes>(timestamp) != timestamp; - bool new_file = min_timestamp_to_list == 0U || (timestamp >= min_timestamp_to_list && timestamp >= last_processed_latest_entry_timestamp_); + bool new_file = !min_timestamp_to_list.has_value() || (timestamp >= min_timestamp_to_list && timestamp >= last_processed_latest_entry_timestamp_); if (new_file) { auto& files_for_timestamp = ordered_files[timestamp]; files_for_timestamp.emplace_back(std::move(file)); @@ -510,9 +519,9 @@ void ListSFTP::listByTrackingTimestamps( } } - uint64_t latest_listed_entry_timestamp_this_cycle = 0U; + std::optional<std::chrono::system_clock::time_point> latest_listed_entry_timestamp_this_cycle; size_t flow_files_created = 0U; - if (ordered_files.size() > 0) { + if (!ordered_files.empty()) { latest_listed_entry_timestamp_this_cycle = ordered_files.crbegin()->first; std::string remote_system_timestamp_precision; @@ -533,20 +542,20 @@ void ListSFTP::listByTrackingTimestamps( */ remote_system_timestamp_precision = TARGET_SYSTEM_TIMESTAMP_PRECISION_SECONDS; } - uint64_t listing_lag = LISTING_LAG_MAP.at(remote_system_timestamp_precision); - logger_->log_debug("The listing lag is %lu ms", listing_lag); + std::chrono::milliseconds listing_lag{LISTING_LAG_MAP.at(remote_system_timestamp_precision)}; + logger_->log_debug("The listing lag is %lu ms", listing_lag.count()); /* If the latest listing time is equal to the last listing time, there are no entries with a newer timestamp than previously seen */ - if (latest_listed_entry_timestamp_this_cycle == last_listed_latest_entry_timestamp_) { - const auto& latest_files = ordered_files.at(latest_listed_entry_timestamp_this_cycle); - uint64_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_run_time - last_run_time_).count(); + if (latest_listed_entry_timestamp_this_cycle == last_listed_latest_entry_timestamp_ && latest_listed_entry_timestamp_this_cycle) { + const auto& latest_files = ordered_files.at(*latest_listed_entry_timestamp_this_cycle); + auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_run_time - last_run_time_); /* If a precision-specific listing lag has not yet elapsed since out last execution, we wait. */ if (elapsed_time < listing_lag) { logger_->log_debug("The latest listed entry timestamp is the same as the last listed entry timestamp (%lu) " "and the listing lag has not yet elapsed (%lu ms < % lu ms). Yielding.", - latest_listed_entry_timestamp_this_cycle, - elapsed_time, - listing_lag); + toUnixTime(latest_listed_entry_timestamp_this_cycle), + elapsed_time.count(), + listing_lag.count()); context->yield(); return; } @@ -559,24 +568,24 @@ void ListSFTP::listByTrackingTimestamps( return latest_identifiers_processed_.count(child.getPath()) == 1U; })) { logger_->log_debug("The latest listed entry timestamp is the same as the last listed entry timestamp (%lu) " - "and all files for that timestamp has been processed. Yielding.", latest_listed_entry_timestamp_this_cycle); + "and all files for that timestamp has been processed. Yielding.", toUnixTime(latest_listed_entry_timestamp_this_cycle)); context->yield(); return; } } else { /* Determine the minimum reliable timestamp based on precision */ - uint64_t minimum_reliable_timestamp = now * 1000 - listing_lag; + auto minimum_reliable_timestamp = now - listing_lag; if (remote_system_timestamp_precision == TARGET_SYSTEM_TIMESTAMP_PRECISION_SECONDS) { - minimum_reliable_timestamp -= minimum_reliable_timestamp % 1000; + std::chrono::floor<std::chrono::seconds>(minimum_reliable_timestamp); } else { - minimum_reliable_timestamp -= minimum_reliable_timestamp % 60000; + std::chrono::floor<std::chrono::minutes>(minimum_reliable_timestamp); } /* If the latest timestamp is not old enough, we wait another cycle */ - if (minimum_reliable_timestamp < latest_listed_entry_timestamp_this_cycle) { + if (latest_listed_entry_timestamp_this_cycle && minimum_reliable_timestamp < latest_listed_entry_timestamp_this_cycle) { logger_->log_debug("Skipping files with latest timestamp because their modification date is not smaller than the minimum reliable timestamp: %lu ms >= %lu ms", - latest_listed_entry_timestamp_this_cycle, - minimum_reliable_timestamp); - ordered_files.erase(latest_listed_entry_timestamp_this_cycle); + toUnixTime(latest_listed_entry_timestamp_this_cycle), + toUnixTime(minimum_reliable_timestamp)); + ordered_files.erase(*latest_listed_entry_timestamp_this_cycle); } } @@ -605,7 +614,7 @@ void ListSFTP::listByTrackingTimestamps( } /* If we have a listing timestamp, it is worth persisting the state */ - if (latest_listed_entry_timestamp_this_cycle != 0U) { + if (latest_listed_entry_timestamp_this_cycle) { bool processed_new_files = flow_files_created > 0U; if (processed_new_files) { auto last_files_it = ordered_files.crbegin(); diff --git a/extensions/sftp/processors/ListSFTP.h b/extensions/sftp/processors/ListSFTP.h index 16d98193f..871aea98a 100644 --- a/extensions/sftp/processors/ListSFTP.h +++ b/extensions/sftp/processors/ListSFTP.h @@ -144,7 +144,7 @@ class ListSFTP : public SFTPProcessorBase { struct Child { Child(); Child(const std::string& parent_path_, std::tuple<std::string /* filename */, std::string /* longentry */, LIBSSH2_SFTP_ATTRIBUTES /* attrs */>&& sftp_child); - std::string getPath() const; + [[nodiscard]] std::string getPath() const; bool directory; std::string parent_path; @@ -155,8 +155,8 @@ class ListSFTP : public SFTPProcessorBase { bool already_loaded_from_cache_; std::chrono::steady_clock::time_point last_run_time_; - uint64_t last_listed_latest_entry_timestamp_; - uint64_t last_processed_latest_entry_timestamp_; + std::optional<std::chrono::system_clock::time_point> last_listed_latest_entry_timestamp_; + std::optional<std::chrono::system_clock::time_point> last_processed_latest_entry_timestamp_; std::set<std::string> latest_identifiers_processed_; bool initial_listing_complete_; diff --git a/extensions/sftp/processors/PutSFTP.cpp b/extensions/sftp/processors/PutSFTP.cpp index 1efe850cb..b167f649e 100644 --- a/extensions/sftp/processors/PutSFTP.cpp +++ b/extensions/sftp/processors/PutSFTP.cpp @@ -117,8 +117,7 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c std::string remote_path; bool disable_directory_listing = false; std::string temp_file_name; - bool last_modified_time_set = false; - int64_t last_modified_time = 0U; + std::optional<std::chrono::system_clock::time_point> last_modified_; bool permissions_set = false; uint32_t permissions = 0U; bool remote_owner_set = false; @@ -143,11 +142,9 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c disable_directory_listing = utils::StringUtils::toBool(value).value_or(false); } context->getProperty(TempFilename, temp_file_name, flow_file); - if (context->getProperty(LastModifiedTime, value, flow_file)) { - if (core::Property::StringToDateTime(value, last_modified_time)) { - last_modified_time_set = true; - } - } + if (context->getProperty(LastModifiedTime, value, flow_file)) + last_modified_ = utils::timeutils::parseDateTimeStr(value); + if (context->getProperty(Permissions, value, flow_file)) { if (core::Property::StringToPermissions(value, permissions)) { permissions_set = true; @@ -328,21 +325,21 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c } /* Set file attributes if needed */ - if (last_modified_time_set || + if (last_modified_ || permissions_set || remote_owner_set || remote_group_set) { utils::SFTPClient::SFTPAttributes attrs; attrs.flags = 0U; - if (last_modified_time_set) { + if (last_modified_) { /* * NiFi doesn't set atime, only mtime, but because they can only be set together, * if we don't want to modify atime, we first have to get it. * Therefore setting them both saves an extra protocol round. */ attrs.flags |= utils::SFTPClient::SFTP_ATTRIBUTE_MTIME | utils::SFTPClient::SFTP_ATTRIBUTE_ATIME; - attrs.mtime = last_modified_time; - attrs.atime = last_modified_time; + attrs.mtime = std::chrono::duration_cast<std::chrono::seconds>(last_modified_->time_since_epoch()).count(); + attrs.atime = std::chrono::duration_cast<std::chrono::seconds>(last_modified_->time_since_epoch()).count(); } if (permissions_set) { attrs.flags |= utils::SFTPClient::SFTP_ATTRIBUTE_PERMISSIONS; diff --git a/extensions/sftp/tests/ListSFTPTests.cpp b/extensions/sftp/tests/ListSFTPTests.cpp index 5f9c7c415..a51961653 100644 --- a/extensions/sftp/tests/ListSFTPTests.cpp +++ b/extensions/sftp/tests/ListSFTPTests.cpp @@ -234,8 +234,7 @@ TEST_CASE_METHOD(ListSFTPTestsFixture, "ListSFTP list one file writes attributes testController.runSession(plan, true); auto file = src_dir + "/vfs/nifi_test/tstFile.ext"; - std::string mtime_str; - REQUIRE(true == utils::timeutils::getDateTimeStr(utils::file::to_time_t(utils::file::last_write_time(file).value()), mtime_str)); + auto mtime_str = utils::timeutils::getDateTimeStr(std::chrono::time_point_cast<std::chrono::seconds>(utils::file::to_sys(utils::file::last_write_time(file).value()))); uint64_t uid, gid; REQUIRE(true == utils::file::FileUtils::get_uid_gid(file, uid, gid)); uint32_t permissions; diff --git a/extensions/standard-processors/processors/LogAttribute.cpp b/extensions/standard-processors/processors/LogAttribute.cpp index dec826cb9..6791a952b 100644 --- a/extensions/standard-processors/processors/LogAttribute.cpp +++ b/extensions/standard-processors/processors/LogAttribute.cpp @@ -111,8 +111,8 @@ void LogAttribute::onTrigger(const std::shared_ptr<core::ProcessContext> &contex message << dashLine; message << "\nStandard FlowFile Attributes"; message << "\n" << "UUID:" << flow->getUUIDStr(); - message << "\n" << "EntryDate:" << utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(flow->getEntryDate().time_since_epoch()).count()); - message << "\n" << "lineageStartDate:" << utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(flow->getlineageStartDate().time_since_epoch()).count()); + message << "\n" << "EntryDate:" << utils::timeutils::getTimeStr(flow->getEntryDate()); + message << "\n" << "lineageStartDate:" << utils::timeutils::getTimeStr(flow->getlineageStartDate()); message << "\n" << "Size:" << flow->getSize() << " Offset:" << flow->getOffset(); message << "\nFlowFile Attributes Map Content"; std::map<std::string, std::string> attrs = flow->getAttributes(); diff --git a/libminifi/include/core/Property.h b/libminifi/include/core/Property.h index 2b81b39c2..5ba79d1b4 100644 --- a/libminifi/include/core/Property.h +++ b/libminifi/include/core/Property.h @@ -165,16 +165,6 @@ class Property { // Compare bool operator <(const Property & right) const; - - static bool StringToDateTime(const std::string& input, int64_t& output) { - int64_t temp = utils::timeutils::parseDateTimeStr(input); - if (temp == -1) { - return false; - } - output = temp; - return true; - } - static bool StringToPermissions(const std::string& input, uint32_t& output) { uint32_t temp = 0U; if (input.size() == 9U) { diff --git a/libminifi/include/utils/TimeUtil.h b/libminifi/include/utils/TimeUtil.h index 5a352947c..dbcf31014 100644 --- a/libminifi/include/utils/TimeUtil.h +++ b/libminifi/include/utils/TimeUtil.h @@ -86,125 +86,45 @@ class SteadyClock : public Clock { } }; -/** - * Returns a string based on TIME_FORMAT, converting - * the parameter to a string - * @param msec milliseconds since epoch - * @returns string representing the time - */ -inline std::string getTimeStr(uint64_t msec, bool enforce_locale = false) { - char date[120]; - time_t second = (time_t) (msec / 1000); - msec = msec % 1000; - strftime(date, sizeof(date) / sizeof(*date), TIME_FORMAT, (enforce_locale == true ? gmtime(&second) : localtime(&second))); - - std::string ret = date; - date[0] = '\0'; - sprintf(date, ".%03llu", (unsigned long long) msec); // NOLINT - - ret += date; - return ret; +inline std::string getTimeStr(std::chrono::system_clock::time_point tp) { + std::ostringstream stream; + date::to_stream(stream, TIME_FORMAT, std::chrono::floor<std::chrono::milliseconds>(tp)); + return stream.str(); } -inline time_t mkgmtime(struct tm* date_time) { -#ifdef WIN32 - return _mkgmtime(date_time); -#else - static const int month_lengths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - static const int month_lengths_leap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - static const auto is_leap_year = [](int year) -> bool { - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); - }; - static const auto num_leap_days = [](int year) -> int { - return (year - 1968) / 4 - (year - 1900) / 100 + (year - 1600) / 400; - }; - - int year = date_time->tm_year + 1900; - time_t result = year - 1970; - result *= 365; - result += num_leap_days(year - 1); - - for (int i = 0; i < 12 && i < date_time->tm_mon; ++i) { - result += is_leap_year(year) ? month_lengths_leap[i] : month_lengths[i]; - } - - result += date_time->tm_mday - 1; - result *= 24; - - result += date_time->tm_hour; - result *= 60; - - result += date_time->tm_min; - result *= 60; - - result += date_time->tm_sec; - return result; -#endif +inline std::optional<std::chrono::sys_seconds> parseDateTimeStr(const std::string& str) { + std::istringstream stream(str); + std::chrono::sys_seconds tp; + date::from_stream(stream, "%Y-%m-%dT%H:%M:%SZ", tp); + if (stream.fail() || (stream.peek() && !stream.eof())) + return std::nullopt; + return tp; } -/** - * Parse a datetime in yyyy-MM-dd'T'HH:mm:ssZ format - * @param str the datetime string - * @returns Unix timestamp - */ -inline int64_t parseDateTimeStr(const std::string& str) { - /** - * There is no strptime on Windows. As long as we have to parse a single date format this is not so bad, - * but if multiple formats will have to be supported in the future, it might be worth it to include - * an strptime implementation from some BSD on Windows. - */ - uint32_t year; - uint8_t month; - uint8_t day; - uint8_t hours; - uint8_t minutes; - uint8_t seconds; - int read = 0; - if (sscanf(str.c_str(), "%4u-%2hhu-%2hhuT%2hhu:%2hhu:%2hhuZ%n", &year, &month, &day, &hours, &minutes, &seconds, &read) != 6) { - return -1; - } - // while it is unlikely that read will be < 0, the conditional adds little cost for a little defensiveness. - if (read < 0 || static_cast<size_t>(read) != str.size()) { - return -1; - } - - if (year < 1970U || - month > 12U || - day > 31U || - hours > 23U || - minutes > 59U || - seconds > 60U) { - return -1; - } - - struct tm timeinfo{}; - timeinfo.tm_year = year - 1900; - timeinfo.tm_mon = month - 1; - timeinfo.tm_mday = day; - timeinfo.tm_hour = hours; - timeinfo.tm_min = minutes; - timeinfo.tm_sec = seconds; - timeinfo.tm_isdst = 0; - - return static_cast<int64_t>(mkgmtime(&timeinfo)); +inline std::string getDateTimeStr(std::chrono::sys_seconds tp) { + std::ostringstream stream; + date::to_stream(stream, "%Y-%m-%dT%H:%M:%SZ", std::chrono::floor<std::chrono::seconds>(tp)); + return stream.str(); } -inline bool getDateTimeStr(int64_t unix_timestamp, std::string& date_time_str) { - if (unix_timestamp > (std::numeric_limits<time_t>::max)() || unix_timestamp < (std::numeric_limits<time_t>::lowest)()) { - return false; - } - time_t time = static_cast<time_t>(unix_timestamp); - struct tm* gmt = gmtime(&time); // NOLINT - if (gmt == nullptr) { - return false; - } - std::array<char, 64U> buf; - if (strftime(buf.data(), buf.size(), "%Y-%m-%dT%H:%M:%SZ", gmt) == 0U) { - return false; - } +inline date::sys_seconds to_sys_time(const std::tm& t) { + using date::year; + using date::month; + using date::day; + using std::chrono::hours; + using std::chrono::minutes; + using std::chrono::seconds; + return date::sys_days{year{t.tm_year + 1900}/(t.tm_mon+1)/t.tm_mday} + hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec}; +} - date_time_str = buf.data(); - return true; +inline date::local_seconds to_local_time(const std::tm& t) { + using date::year; + using date::month; + using date::day; + using std::chrono::hours; + using std::chrono::minutes; + using std::chrono::seconds; + return date::local_days{year{t.tm_year + 1900}/(t.tm_mon+1)/t.tm_mday} + hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec}; } namespace details { diff --git a/libminifi/include/utils/tls/CertificateUtils.h b/libminifi/include/utils/tls/CertificateUtils.h index 73e7011fc..64f0d65f7 100644 --- a/libminifi/include/utils/tls/CertificateUtils.h +++ b/libminifi/include/utils/tls/CertificateUtils.h @@ -33,12 +33,7 @@ #include "WindowsCertStoreLocation.h" -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace utils { -namespace tls { +namespace org::apache::nifi::minifi::utils::tls { class ssl_error_category : public std::error_category { public: @@ -114,11 +109,6 @@ std::error_code processP12Certificate(const std::string& cert_file, const std::s std::error_code processPEMCertificate(const std::string& cert_file, const std::optional<std::string>& passphrase, const CertHandler& handler); -} // namespace tls -} // namespace utils -} // namespace minifi -} // namespace nifi -} // namespace apache -} // namespace org +} // namespace org::apache::nifi::minifi::utils::tls #endif // OPENSSL_SUPPORT diff --git a/libminifi/src/controllers/SSLContextService.cpp b/libminifi/src/controllers/SSLContextService.cpp index d91563f9f..76c178aa7 100644 --- a/libminifi/src/controllers/SSLContextService.cpp +++ b/libminifi/src/controllers/SSLContextService.cpp @@ -149,7 +149,7 @@ bool SSLContextService::configure_ssl_context(SSL_CTX *ctx) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr); if (!IsNullOrEmpty(ca_certificate_)) { - if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0) == 0) { + if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), nullptr) == 0) { core::logging::LOG_ERROR(logger_) << "Cannot load CA certificate, exiting, " << getLatestOpenSSLErrorString(); return false; } @@ -545,7 +545,7 @@ void SSLContextService::initializeProperties() { void SSLContextService::verifyCertificateExpiration() { auto verify = [&] (const std::string& cert_file, const utils::tls::X509_unique_ptr& cert) { if (auto end_date = utils::tls::getCertificateExpiration(cert)) { - std::string end_date_str = utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(end_date->time_since_epoch()).count()); + std::string end_date_str = utils::timeutils::getTimeStr(*end_date); if (end_date.value() < std::chrono::system_clock::now()) { core::logging::LOG_ERROR(logger_) << "Certificate in '" << cert_file << "' expired at " << end_date_str; } else if (auto diff = end_date.value() - std::chrono::system_clock::now(); diff < std::chrono::weeks{2}) { diff --git a/libminifi/src/utils/tls/CertificateUtils.cpp b/libminifi/src/utils/tls/CertificateUtils.cpp index 6fe4fe1bf..453a8d750 100644 --- a/libminifi/src/utils/tls/CertificateUtils.cpp +++ b/libminifi/src/utils/tls/CertificateUtils.cpp @@ -30,12 +30,7 @@ #include "utils/tls/TLSUtils.h" #include "utils/TimeUtil.h" -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace utils { -namespace tls { +namespace org::apache::nifi::minifi::utils::tls { const ssl_error_category& ssl_error_category::get() { static ssl_error_category instance; @@ -181,7 +176,7 @@ std::optional<std::chrono::system_clock::time_point> getCertificateExpiration(co if (ret == -1) { return {}; } - return std::chrono::system_clock::from_time_t(utils::timeutils::mkgmtime(&end)); + return utils::timeutils::to_sys_time(end); } std::error_code processP12Certificate(const std::string& cert_file, const std::string& passphrase, const CertHandler& handler) { @@ -265,11 +260,6 @@ std::error_code processPEMCertificate(const std::string& cert_file, const std::o return {}; } -} // namespace tls -} // namespace utils -} // namespace minifi -} // namespace nifi -} // namespace apache -} // namespace org +} // namespace org::apache::nifi::minifi::utils::tls #endif // OPENSSL_SUPPORT diff --git a/libminifi/test/unit/PropertyTests.cpp b/libminifi/test/unit/PropertyTests.cpp index b35b0aa18..c2eb1cfc3 100644 --- a/libminifi/test/unit/PropertyTests.cpp +++ b/libminifi/test/unit/PropertyTests.cpp @@ -19,10 +19,10 @@ #include <string> #include "core/Property.h" -#include "../../include/core/Property.h" #include "utils/StringUtils.h" #include "../TestBase.h" #include "../Catch.h" + namespace { enum class ConversionTestTarget { MS, NS }; @@ -126,35 +126,4 @@ TEST_CASE("Test Permissions Conversion", "[testPermissions]") { REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToPermissions("foobar", permissions)); } - -TEST_CASE("Test DateTime Conversion", "[testDateTime]") { - int64_t timestamp = 0LL; - - REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00Z", timestamp)); - REQUIRE(0LL == timestamp); - - REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:59:59Z", timestamp)); - REQUIRE(3600 - 1 == timestamp); - - REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2000-06-17T12:34:21Z", timestamp)); - REQUIRE(961245261LL == timestamp); - - REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2038-01-19T03:14:07Z", timestamp)); - REQUIRE(2147483647LL == timestamp); - - REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2065-01-24T05:20:00Z", timestamp)); - REQUIRE(3000000000LL == timestamp); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01A00:00:00Z", timestamp)); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00", timestamp)); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00Zfoo", timestamp)); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1969-01-01T00:00:00Z", timestamp)); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-13-01T00:00:00Z", timestamp)); - - REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("foobar", timestamp)); -} } // namespace diff --git a/libminifi/test/unit/TimeUtilTests.cpp b/libminifi/test/unit/TimeUtilTests.cpp index 0a96e5134..bd2518c02 100644 --- a/libminifi/test/unit/TimeUtilTests.cpp +++ b/libminifi/test/unit/TimeUtilTests.cpp @@ -21,79 +21,78 @@ using namespace std::literals::chrono_literals; -namespace { - constexpr int ONE_HOUR = 60 * 60; - constexpr int ONE_DAY = 24 * ONE_HOUR; - - struct tm createTm(int year, int month, int day, int hour, int minute, int second, bool is_dst = false) { - struct tm date_time; - date_time.tm_year = year - 1900; - date_time.tm_mon = month - 1; - date_time.tm_mday = day; - date_time.tm_hour = hour; - date_time.tm_min = minute; - date_time.tm_sec = second; - date_time.tm_isdst = is_dst ? 1 : 0; - return date_time; - } - - void mkgmtimeTestHelper(time_t expected, int year, int month, int day, int hour, int minute, int second) { - using org::apache::nifi::minifi::utils::timeutils::mkgmtime; - struct tm date_time = createTm(year, month, day, hour, minute, second); - REQUIRE(mkgmtime(&date_time) == expected); - } -} // namespace +TEST_CASE("parseDateTimeStr() works correctly", "[parseDateTimeStr]") { + using org::apache::nifi::minifi::utils::timeutils::parseDateTimeStr; -TEST_CASE("mkgmtime() works correctly", "[mkgmtime]") { - mkgmtimeTestHelper(0, 1970, 1, 1, 0, 0, 0); - for (int hour = 0; hour < 24; ++hour) { - mkgmtimeTestHelper((hour + 1) * ONE_HOUR - 1, 1970, 1, 1, hour, 59, 59); - } - - mkgmtimeTestHelper(ONE_DAY, 1970, 1, 2, 0, 0, 0); - mkgmtimeTestHelper(31 * ONE_DAY, 1970, 2, 1, 0, 0, 0); - mkgmtimeTestHelper(365 * ONE_DAY, 1971, 1, 1, 0, 0, 0); - - mkgmtimeTestHelper(793929600, 1995, 2, 28, 0, 0, 0); - mkgmtimeTestHelper(793929600 + ONE_DAY, 1995, 3, 1, 0, 0, 0); - mkgmtimeTestHelper(825465600, 1996, 2, 28, 0, 0, 0); - mkgmtimeTestHelper(825465600 + ONE_DAY, 1996, 2, 29, 0, 0, 0); - mkgmtimeTestHelper(951696000, 2000, 2, 28, 0, 0, 0); - mkgmtimeTestHelper(951696000 + ONE_DAY, 2000, 2, 29, 0, 0, 0); - mkgmtimeTestHelper(4107456000, 2100, 2, 28, 0, 0, 0); - mkgmtimeTestHelper(4107456000 + ONE_DAY, 2100, 3, 1, 0, 0, 0); - - mkgmtimeTestHelper(1513104856, 2017, 12, 12, 18, 54, 16); - mkgmtimeTestHelper(1706655675, 2024, 1, 30, 23, 01, 15); - mkgmtimeTestHelper(3710453630, 2087, 7, 31, 01, 33, 50); + CHECK(*parseDateTimeStr("1970-01-01T00:00:00Z") == std::chrono::sys_seconds{0s}); + CHECK(*parseDateTimeStr("1970-01-01T00:59:59Z") == std::chrono::sys_seconds{1h - 1s}); + + CHECK(*parseDateTimeStr("1970-01-02T00:00:00Z") == std::chrono::sys_seconds{std::chrono::days(1)}); + CHECK(*parseDateTimeStr("1970-02-01T00:00:00Z") == std::chrono::sys_seconds{31 * std::chrono::days(1)}); + CHECK(*parseDateTimeStr("1971-01-01T00:00:00Z") == std::chrono::sys_seconds{365 * std::chrono::days(1)}); + + CHECK(*parseDateTimeStr("1995-02-28T00:00:00Z") == std::chrono::sys_seconds{793929600s}); + CHECK(*parseDateTimeStr("1995-03-01T00:00:00Z") == std::chrono::sys_seconds{793929600s + std::chrono::days(1)}); + CHECK(*parseDateTimeStr("1996-02-28T00:00:00Z") == std::chrono::sys_seconds{825465600s}); + CHECK(*parseDateTimeStr("1996-02-29T00:00:00Z") == std::chrono::sys_seconds{825465600s + std::chrono::days(1)}); + CHECK(*parseDateTimeStr("2000-02-28T00:00:00Z") == std::chrono::sys_seconds{951696000s}); + CHECK(*parseDateTimeStr("2000-02-29T00:00:00Z") == std::chrono::sys_seconds{951696000s + std::chrono::days(1)}); + CHECK(*parseDateTimeStr("2100-02-28T00:00:00Z") == std::chrono::sys_seconds{4107456000s}); + CHECK(*parseDateTimeStr("2100-03-01T00:00:00Z") == std::chrono::sys_seconds{4107456000s + std::chrono::days(1)}); + + CHECK(*parseDateTimeStr("2017-12-12T18:54:16Z") == std::chrono::sys_seconds{1513104856s}); + CHECK(*parseDateTimeStr("2024-01-30T23:01:15Z") == std::chrono::sys_seconds{1706655675s}); + CHECK(*parseDateTimeStr("2087-07-31T01:33:50Z") == std::chrono::sys_seconds{3710453630s}); } -TEST_CASE("parseDateTimeStr() works correctly", "[parseDateTimeStr]") { - using org::apache::nifi::minifi::utils::timeutils::parseDateTimeStr; - REQUIRE(parseDateTimeStr("1970-01-01T00:00:00Z") == 0); - REQUIRE(parseDateTimeStr("1970-01-01T00:59:59Z") == ONE_HOUR - 1); - - REQUIRE(parseDateTimeStr("1970-01-02T00:00:00Z") == ONE_DAY); - REQUIRE(parseDateTimeStr("1970-02-01T00:00:00Z") == 31 * ONE_DAY); - REQUIRE(parseDateTimeStr("1971-01-01T00:00:00Z") == 365 * ONE_DAY); - - REQUIRE(parseDateTimeStr("1995-02-28T00:00:00Z") == 793929600); - REQUIRE(parseDateTimeStr("1995-03-01T00:00:00Z") == 793929600 + ONE_DAY); - REQUIRE(parseDateTimeStr("1996-02-28T00:00:00Z") == 825465600); - REQUIRE(parseDateTimeStr("1996-02-29T00:00:00Z") == 825465600 + ONE_DAY); - REQUIRE(parseDateTimeStr("2000-02-28T00:00:00Z") == 951696000); - REQUIRE(parseDateTimeStr("2000-02-29T00:00:00Z") == 951696000 + ONE_DAY); - REQUIRE(parseDateTimeStr("2100-02-28T00:00:00Z") == 4107456000); - REQUIRE(parseDateTimeStr("2100-03-01T00:00:00Z") == 4107456000 + ONE_DAY); - - REQUIRE(parseDateTimeStr("2017-12-12T18:54:16Z") == 1513104856); - REQUIRE(parseDateTimeStr("2024-01-30T23:01:15Z") == 1706655675); - REQUIRE(parseDateTimeStr("2087-07-31T01:33:50Z") == 3710453630); +TEST_CASE("getDateTimeStr() works correctly", "[getDateTimeStr]") { + using org::apache::nifi::minifi::utils::timeutils::getDateTimeStr; + + CHECK("1970-01-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{0s})); + CHECK("1970-01-01T00:59:59Z" == getDateTimeStr(std::chrono::sys_seconds{1h - 1s})); + + CHECK("1970-01-02T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{std::chrono::days(1)})); + CHECK("1970-02-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{31 * std::chrono::days(1)})); + CHECK("1971-01-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{365 * std::chrono::days(1)})); + + CHECK("1995-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{793929600s})); + CHECK("1995-03-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{793929600s + std::chrono::days(1)})); + CHECK("1996-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{825465600s})); + CHECK("1996-02-29T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{825465600s + std::chrono::days(1)})); + CHECK("2000-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{951696000s})); + CHECK("2000-02-29T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{951696000s + std::chrono::days(1)})); + CHECK("2100-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{4107456000s})); + CHECK("2100-03-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{4107456000s + std::chrono::days(1)})); + + CHECK("2017-12-12T18:54:16Z" == getDateTimeStr(std::chrono::sys_seconds{1513104856s})); + CHECK("2024-01-30T23:01:15Z" == getDateTimeStr(std::chrono::sys_seconds{1706655675s})); + CHECK("2087-07-31T01:33:50Z" == getDateTimeStr(std::chrono::sys_seconds{3710453630s})); } TEST_CASE("Test time conversion", "[testtimeconversion]") { using org::apache::nifi::minifi::utils::timeutils::getTimeStr; - REQUIRE("2017-02-16 20:14:56.196" == getTimeStr(1487276096196, true)); + CHECK("2017-02-16 20:14:56.196" == getTimeStr(std::chrono::system_clock::time_point{1487276096196ms})); +} + +TEST_CASE("Test DateTime Conversion", "[testDateTime]") { + using namespace date::literals; + using namespace std::literals::chrono_literals; + using date::year_month_day; + using date::sys_days; + using utils::timeutils::parseDateTimeStr; + + CHECK(sys_days(date::year_month_day(1970_y/01/01)) == parseDateTimeStr("1970-01-01T00:00:00Z")); + CHECK(sys_days(year_month_day(1970_y/01/01)) + 0h + 59min + 59s == parseDateTimeStr("1970-01-01T00:59:59Z")); + CHECK(sys_days(year_month_day(2000_y/06/17)) + 12h + 34min + 21s == parseDateTimeStr("2000-06-17T12:34:21Z")); + CHECK(sys_days(year_month_day(2038_y/01/19)) + 3h + 14min + 7s == parseDateTimeStr("2038-01-19T03:14:07Z")); + CHECK(sys_days(year_month_day(2065_y/01/24)) + 5h + 20min + 0s == parseDateTimeStr("2065-01-24T05:20:00Z")); + CHECK(sys_days(year_month_day(1969_y/01/01)) == parseDateTimeStr("1969-01-01T00:00:00Z")); + + CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01A00:00:00Z")); + CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01T00:00:00")); + CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01T00:00:00Zfoo")); + CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-13-01T00:00:00Z")); + CHECK_FALSE(utils::timeutils::parseDateTimeStr("foobar")); } TEST_CASE("Test system_clock epoch", "[systemclockepoch]") { @@ -107,7 +106,7 @@ TEST_CASE("Test system_clock epoch", "[systemclockepoch]") { TEST_CASE("Test clock resolutions", "[clockresolutiontests]") { using namespace std::chrono; CHECK(std::is_constructible<system_clock::duration, std::chrono::microseconds>::value); // The resolution of the system_clock is at least microseconds - CHECK(std::is_constructible<steady_clock::duration, std::chrono::microseconds>::value); // The resolution of the system_clock is at least microseconds + CHECK(std::is_constructible<steady_clock::duration, std::chrono::microseconds>::value); // The resolution of the steady_clock is at least microseconds CHECK(std::is_constructible<high_resolution_clock::duration, std::chrono::nanoseconds>::value); // The resolution of the high_resolution_clock is at least nanoseconds }
