diff --git a/CMakeLists.txt b/CMakeLists.txt index d1220305c..c89d74038 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(AGENT_VERSION_MAJOR 2) set(AGENT_VERSION_MINOR 6) set(AGENT_VERSION_PATCH 0) -set(AGENT_VERSION_BUILD 3) +set(AGENT_VERSION_BUILD 4) set(AGENT_VERSION_RC "") # This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent diff --git a/src/mtconnect/agent.cpp b/src/mtconnect/agent.cpp index 8efbb565c..52544662e 100644 --- a/src/mtconnect/agent.cpp +++ b/src/mtconnect/agent.cpp @@ -252,7 +252,7 @@ namespace mtconnect { catch (std::runtime_error &e) { LOG(fatal) << "Cannot start server: " << e.what(); - std::exit(1); + throw FatalException(e.what()); } m_started = true; @@ -436,14 +436,14 @@ namespace mtconnect { LOG(fatal) << "Error loading xml configuration: " + deviceFile; LOG(fatal) << "Error detail: " << e.what(); cerr << e.what() << endl; - throw e; + throw FatalException(e.what()); } catch (exception &f) { LOG(fatal) << "Error loading xml configuration: " + deviceFile; LOG(fatal) << "Error detail: " << f.what(); cerr << f.what() << endl; - throw f; + throw FatalException(f.what()); } } @@ -525,6 +525,10 @@ namespace mtconnect { if (changed) loadCachedProbe(); } + catch (FatalException &e) + { + throw e; + } catch (runtime_error &e) { for (auto device : devices) @@ -832,7 +836,7 @@ namespace mtconnect { { for (auto &e : errors) LOG(fatal) << "Error creating the agent device: " << e->what(); - throw EntityError("Cannot create AgentDevice"); + throw FatalException("Cannot create AgentDevice"); } addDevice(m_agentDevice); } @@ -870,14 +874,14 @@ namespace mtconnect { LOG(fatal) << "Error loading xml configuration: " + configXmlPath; LOG(fatal) << "Error detail: " << e.what(); cerr << e.what() << endl; - throw e; + throw FatalException(e.what()); } catch (exception &f) { LOG(fatal) << "Error loading xml configuration: " + configXmlPath; LOG(fatal) << "Error detail: " << f.what(); cerr << f.what() << endl; - throw f; + throw FatalException(f.what()); } return {}; @@ -976,9 +980,13 @@ namespace mtconnect { auto di = m_dataItemMap[d->getId()].lock(); if (di && di != d) { - LOG(fatal) << "Duplicate DataItem id " << d->getId() - << " for device: " << *device->getComponentName(); - std::exit(1); + stringstream msg; + + msg << "Duplicate DataItem id " << d->getId() + << " for device: " << *device->getComponentName() + << ". Try using configuration option CreateUniqueIds to resolve."; + LOG(fatal) << msg.str(); + throw FatalException(msg.str()); } } else @@ -1008,9 +1016,10 @@ namespace mtconnect { if (old != idx.end()) { // Update existing device - LOG(fatal) << "Device " << *device->getUuid() << " already exists. " - << " Update not supported yet"; - std::exit(1); + stringstream msg; + msg << "Device " << *device->getUuid() << " already exists. " + << " Update not supported yet"; + throw msg; } else { diff --git a/src/mtconnect/configuration/agent_config.cpp b/src/mtconnect/configuration/agent_config.cpp index 48ee6f8b2..2b6b9a67c 100644 --- a/src/mtconnect/configuration/agent_config.cpp +++ b/src/mtconnect/configuration/agent_config.cpp @@ -182,12 +182,12 @@ namespace mtconnect::configuration { buffer << file.rdbuf(); FileFormat fmt = MTCONNECT; - if (ends_with(m_configFile.string(), "json")) + if (m_configFile.string().ends_with("json")) { LOG(debug) << "Parsing json configuration"; fmt = JSON; } - else if (ends_with(m_configFile.string(), "xml")) + else if (m_configFile.string().ends_with("xml")) { LOG(debug) << "Parsing xml configuration"; fmt = XML; @@ -392,7 +392,7 @@ namespace mtconnect::configuration { m_monitorTimer.async_wait(boost::bind(&AgentConfiguration::monitorFiles, this, _1)); } - void AgentConfiguration::start() + int AgentConfiguration::start() { if (m_monitorFiles) { @@ -411,7 +411,7 @@ namespace mtconnect::configuration { m_context->setThreadCount(m_workerThreadCount); m_beforeStartHooks.exec(*this); m_agent->start(); - m_context->start(); + return m_context->start(); } void AgentConfiguration::stop() @@ -879,12 +879,12 @@ namespace mtconnect::configuration { LOG(fatal) << "Cannot find device configuration file"; logPaths(LOG_LEVEL(fatal), m_configPaths); - throw runtime_error(((string) "Please make sure the configuration " - "file probe.xml or Devices.xml is in the current " - "directory or specify the correct file " - "in the configuration file " + - m_configFile.string() + " using Devices = ") - .c_str()); + throw FatalException(((string) "Please make sure the configuration " + "file probe.xml or Devices.xml is in the current " + "directory or specify the correct file " + "in the configuration file " + + m_configFile.string() + " using Devices = ") + .c_str()); } m_name = get(options[configuration::ServiceName]); @@ -958,7 +958,7 @@ namespace mtconnect::configuration { if (host.empty()) { LOG(fatal) << "Malformed URL in configuration file: '" << url << "', exiting"; - exit(1); + throw FatalException(); } options[configuration::Host] = host; @@ -1252,4 +1252,3 @@ namespace mtconnect::configuration { return false; } } // namespace mtconnect::configuration - diff --git a/src/mtconnect/configuration/agent_config.hpp b/src/mtconnect/configuration/agent_config.hpp index 72191af28..593ae6dca 100644 --- a/src/mtconnect/configuration/agent_config.hpp +++ b/src/mtconnect/configuration/agent_config.hpp @@ -104,7 +104,8 @@ namespace mtconnect { /// @brief stops the agent. Used in daemons. void stop() override; /// @brief starts the agent. Used in daemons. - void start() override; + /// @return 0 on success + int start() override; /// @brief initializes the configuration of the agent from the command line parameters /// @param[in] options command line parameters void initialize(const boost::program_options::variables_map &options) override; diff --git a/src/mtconnect/configuration/async_context.hpp b/src/mtconnect/configuration/async_context.hpp index aa92c3e5b..6c4694913 100644 --- a/src/mtconnect/configuration/async_context.hpp +++ b/src/mtconnect/configuration/async_context.hpp @@ -22,6 +22,7 @@ #include "mtconnect/config.hpp" #include "mtconnect/logging.hpp" +#include "mtconnect/utilities.hpp" namespace mtconnect::configuration { @@ -63,46 +64,96 @@ namespace mtconnect::configuration { void setThreadCount(int threads) { m_threadCount = threads; } /// @brief start `m_threadCount` worker threads - void start() + /// @returns the exit code + int start() { - m_running = true; - m_paused = false; - do + m_exitCode = 0; + try { - for (int i = 0; i < m_threadCount; i++) - { - m_workers.emplace_back(boost::thread([this]() { m_context.run(); })); - } - auto &first = m_workers.front(); - while (m_running && !m_paused) + m_running = true; + m_paused = false; + do { - if (!first.try_join_for(boost::chrono::seconds(5)) && !m_running) + for (int i = 0; i < m_threadCount; i++) + { + m_workers.emplace_back(boost::thread([this]() { + try + { + m_context.run(); + } + + catch (FatalException &e) + { + LOG(fatal) << "Fatal exception occurred: " << e.what(); + stop(); + m_exitCode = 1; + } + catch (std::exception &e) + { + LOG(fatal) << "Uncaught exception occurred: " << e.what(); + stop(); + m_exitCode = 1; + } + catch (...) + { + LOG(fatal) << "Unknown fatal exception occurred"; + stop(); + m_exitCode = 1; + } + })); + } + auto &first = m_workers.front(); + while (m_running && !m_paused) { - if (!first.try_join_for(boost::chrono::seconds(5))) - m_context.stop(); + if (!first.try_join_for(boost::chrono::seconds(5)) && !m_running) + { + if (!first.try_join_for(boost::chrono::seconds(5))) + m_context.stop(); + } } - } - for (auto &w : m_workers) - { - w.join(); - } - m_workers.clear(); + for (auto &w : m_workers) + { + w.join(); + } + m_workers.clear(); - if (m_delayedStop.joinable()) - m_delayedStop.join(); + if (m_delayedStop.joinable()) + m_delayedStop.join(); - if (m_syncCallback) - { - m_syncCallback(*this); - if (m_running) + if (m_syncCallback && m_exitCode == 0) { - m_syncCallback = nullptr; - restart(); + m_syncCallback(*this); + if (m_running) + { + m_syncCallback = nullptr; + restart(); + } } - } - } while (m_running); + } while (m_running); + } + + catch (FatalException &e) + { + LOG(fatal) << "Fatal exception occurred: " << e.what(); + stop(); + m_exitCode = 1; + } + catch (std::exception &e) + { + LOG(fatal) << "Uncaught exception occurred: " << e.what(); + stop(); + m_exitCode = 1; + } + catch (...) + { + LOG(fatal) << "Unknown fatal exception occurred"; + stop(); + m_exitCode = 1; + } + + return m_exitCode; } /// @brief pause the worker threads. Sets a callback when the threads are paused. @@ -190,6 +241,7 @@ namespace mtconnect::configuration { int m_threadCount = 1; bool m_running = false; bool m_paused = false; + int m_exitCode = 0; }; } // namespace mtconnect::configuration diff --git a/src/mtconnect/configuration/service.cpp b/src/mtconnect/configuration/service.cpp index a98185912..1709937e7 100644 --- a/src/mtconnect/configuration/service.cpp +++ b/src/mtconnect/configuration/service.cpp @@ -176,6 +176,8 @@ namespace mtconnect { using namespace std; + int res = 0; + try { // If command-line parameter is "install", install the service. If debug or run @@ -208,9 +210,9 @@ namespace mtconnect { m_isDebug = true; initialize(options); - start(); + res = start(); std::thread cmd(commandLine); - return 0; + return res; } else { @@ -236,14 +238,16 @@ namespace mtconnect { { LOG(fatal) << "Agent top level exception: " << e.what(); std::cerr << "Agent top level exception: " << e.what() << std::endl; + res = 1; } catch (std::string &s) { LOG(fatal) << "Agent top level exception: " << s; std::cerr << "Agent top level exception: " << s << std::endl; + res = 1; } - return 0; + return res; } bool MTConnectService::isElevated() @@ -841,8 +845,7 @@ namespace mtconnect { usage(1); } - start(); - return 0; + return start(); } void MTConnectService::install() {} diff --git a/src/mtconnect/configuration/service.hpp b/src/mtconnect/configuration/service.hpp index 7795965be..60e6f736d 100644 --- a/src/mtconnect/configuration/service.hpp +++ b/src/mtconnect/configuration/service.hpp @@ -44,7 +44,7 @@ namespace mtconnect { /// @brief stop the srvice virtual void stop() = 0; /// @brief start the service - virtual void start() = 0; + virtual int start() = 0; /// @brief set the name of the service /// @param[in] name name of the service diff --git a/src/mtconnect/device_model/agent_device.cpp b/src/mtconnect/device_model/agent_device.cpp index 287e4065a..d88257488 100644 --- a/src/mtconnect/device_model/agent_device.cpp +++ b/src/mtconnect/device_model/agent_device.cpp @@ -66,6 +66,7 @@ namespace mtconnect { { LOG(fatal) << "Cannot create AgentDevice: " << e->what(); } + throw FatalException(); } } diff --git a/src/mtconnect/device_model/data_item/data_item.cpp b/src/mtconnect/device_model/data_item/data_item.cpp index a6828900c..d6dfd230a 100644 --- a/src/mtconnect/device_model/data_item/data_item.cpp +++ b/src/mtconnect/device_model/data_item/data_item.cpp @@ -130,7 +130,7 @@ namespace mtconnect { auto &category = get("category"); auto units = maybeGet("units"); - if (units && ends_with(*units, "3D")) + if (units && units->ends_with("3D")) m_specialClass = THREE_SPACE_CLS; if (category == "SAMPLE") diff --git a/src/mtconnect/device_model/device.cpp b/src/mtconnect/device_model/device.cpp index fea72bc30..a6e7a9250 100644 --- a/src/mtconnect/device_model/device.cpp +++ b/src/mtconnect/device_model/device.cpp @@ -60,9 +60,11 @@ namespace mtconnect { { if (auto it = m_dataItems.get().find(di->getId()); it != m_dataItems.get().end()) { - LOG(fatal) << "Device " << getName() << ": Duplicatie data item id '" << di->getId() - << "', Exiting"; - exit(1); + stringstream msg; + msg << "Device " << getName() << ": Duplicatie data item id '" << di->getId() + << "', Exiting"; + LOG(fatal) << msg.str(); + throw FatalException(msg.str()); } if (di->hasProperty("Source") && di->getSource()->hasValue()) @@ -93,9 +95,11 @@ namespace mtconnect { auto [id, added] = m_dataItems.emplace(di); if (!added) { - LOG(fatal) << "Device " << getName() << ": DataItem '" << di->getId() - << " could not be added, exiting"; - exit(1); + stringstream msg; + msg << "Device " << getName() << ": DataItem '" << di->getId() + << " could not be added, exiting"; + LOG(fatal) << msg.str(); + throw FatalException(msg.str()); } } diff --git a/src/mtconnect/entity/factory.cpp b/src/mtconnect/entity/factory.cpp index eb93aebd5..3e1591760 100644 --- a/src/mtconnect/entity/factory.cpp +++ b/src/mtconnect/entity/factory.cpp @@ -188,7 +188,7 @@ namespace mtconnect { // If the property is a namespace declaration, then // remove it if it is related to mtconnect, otherwise // allow it to pass through. - if (ba::starts_with(p.first.str(), "xmlns"s)) + if (p.first.str().starts_with("xmlns"sv)) { if (holds_alternative(p.second) && ba::contains(get(p.second), "mtconnect"s)) diff --git a/src/mtconnect/entity/xml_printer.cpp b/src/mtconnect/entity/xml_printer.cpp index 3cfb0ccb4..66d461886 100644 --- a/src/mtconnect/entity/xml_printer.cpp +++ b/src/mtconnect/entity/xml_printer.cpp @@ -19,8 +19,8 @@ #include -#include #include +#include #include "mtconnect/logging.hpp" #include "mtconnect/printer/xml_printer_helper.hpp" diff --git a/src/mtconnect/observation/observation.cpp b/src/mtconnect/observation/observation.cpp index 58f276b16..e50f9d46c 100644 --- a/src/mtconnect/observation/observation.cpp +++ b/src/mtconnect/observation/observation.cpp @@ -66,40 +66,40 @@ namespace mtconnect { // regex(".+TimeSeries$") factory->registerFactory( - [](const std::string &name) { return ends_with(name, "TimeSeries"); }, + [](const std::string &name) { return name.ends_with("TimeSeries"); }, Timeseries::getFactory()); - factory->registerFactory([](const std::string &name) { return ends_with(name, "DataSet"); }, + factory->registerFactory([](const std::string &name) { return name.ends_with("DataSet"); }, DataSetEvent::getFactory()); - factory->registerFactory([](const std::string &name) { return ends_with(name, "Table"); }, + factory->registerFactory([](const std::string &name) { return name.ends_with("Table"); }, TableEvent::getFactory()); factory->registerFactory( - [](const std::string &name) { return starts_with(name, "Condition:"); }, + [](const std::string &name) { return name.starts_with("Condition:"); }, Condition::getFactory()); factory->registerFactory( [](const std::string &name) { - return starts_with(name, "Samples:") && ends_with(name, ":3D"); + return name.starts_with("Samples:") && name.ends_with(":3D"); }, ThreeSpaceSample::getFactory()); factory->registerFactory( [](const std::string &name) { - return starts_with(name, "Events:") && ends_with(name, ":3D"); + return name.starts_with("Events:") && name.ends_with(":3D"); }, ThreeSpaceSample::getFactory()); factory->registerFactory( - [](const std::string &name) { return starts_with(name, "Samples:"); }, + [](const std::string &name) { return name.starts_with("Samples:"); }, Sample::getFactory()); factory->registerFactory( [](const std::string &name) { - return starts_with(name, "Events:") && ends_with(name, ":DOUBLE"); + return name.starts_with("Events:") && name.ends_with(":DOUBLE"); }, DoubleEvent::getFactory()); factory->registerFactory( [](const std::string &name) { - return starts_with(name, "Events:") && ends_with(name, ":INT"); + return name.starts_with("Events:") && name.ends_with(":INT"); }, IntEvent::getFactory()); factory->registerFactory( - [](const std::string &name) { return starts_with(name, "Events:"); }, + [](const std::string &name) { return name.starts_with("Events:"); }, Event::getFactory()); } return factory; diff --git a/src/mtconnect/parser/xml_parser.cpp b/src/mtconnect/parser/xml_parser.cpp index 9f5363e75..3a03709a4 100644 --- a/src/mtconnect/parser/xml_parser.cpp +++ b/src/mtconnect/parser/xml_parser.cpp @@ -227,7 +227,7 @@ namespace mtconnect::parser { xmlXPathFreeContext(xpathCtx); LOG(fatal) << "Cannot parse XML file: " << e; - throw; + throw FatalException(e); } catch (...) { @@ -237,7 +237,7 @@ namespace mtconnect::parser { if (xpathCtx) xmlXPathFreeContext(xpathCtx); - throw; + throw FatalException(); } return deviceList; @@ -272,7 +272,7 @@ namespace mtconnect::parser { catch (string e) { LOG(fatal) << "Cannot parse XML document: " << e; - throw; + throw FatalException(); } return device; @@ -312,7 +312,7 @@ namespace mtconnect::parser { catch (string e) { LOG(fatal) << "Cannot parse XML document: " << e; - throw; + throw FatalException(); } } diff --git a/src/mtconnect/pipeline/pipeline.hpp b/src/mtconnect/pipeline/pipeline.hpp index 8fa7b8594..a6ce14c67 100644 --- a/src/mtconnect/pipeline/pipeline.hpp +++ b/src/mtconnect/pipeline/pipeline.hpp @@ -17,9 +17,10 @@ #pragma once -#include #include +#include + #include "mtconnect/config.hpp" #include "pipeline_context.hpp" #include "pipeline_contract.hpp" diff --git a/src/mtconnect/printer/xml_printer.cpp b/src/mtconnect/printer/xml_printer.cpp index 3ea09f277..06c0da048 100644 --- a/src/mtconnect/printer/xml_printer.cpp +++ b/src/mtconnect/printer/xml_printer.cpp @@ -24,8 +24,8 @@ #include #include -#include #include +#include #include "mtconnect/asset/asset.hpp" #include "mtconnect/asset/cutting_tool.hpp" diff --git a/src/mtconnect/ruby/embedded.cpp b/src/mtconnect/ruby/embedded.cpp index f461d086b..57365e03e 100644 --- a/src/mtconnect/ruby/embedded.cpp +++ b/src/mtconnect/ruby/embedded.cpp @@ -186,18 +186,18 @@ namespace mtconnect::ruby { if (mrb_false_p(res)) { LOG(fatal) << "Error loading file " << *modulePath << ": exiting agent"; - exit(1); + throw FatalException("Fatal error loading module"); } } catch (std::exception ex) { LOG(fatal) << "Failed to load module: " << *modulePath << ": " << ex.what(); - exit(1); + throw FatalException("Fatal error loading module"); } catch (...) { LOG(fatal) << "Failed to load module: " << *modulePath; - exit(1); + throw FatalException("Fatal error loading module"); } if (fp != nullptr) { diff --git a/src/mtconnect/sink/rest_sink/file_cache.cpp b/src/mtconnect/sink/rest_sink/file_cache.cpp index 4c1ae8f5c..ceec74ffc 100644 --- a/src/mtconnect/sink/rest_sink/file_cache.cpp +++ b/src/mtconnect/sink/rest_sink/file_cache.cpp @@ -263,7 +263,7 @@ namespace mtconnect::sink::rest_sink { for (const auto &dir : m_directories) { - if (boost::starts_with(name, dir.first)) + if (name.starts_with(dir.first)) { auto fileName = boost::erase_first_copy(name, dir.first); if (fileName.empty()) @@ -382,7 +382,7 @@ namespace mtconnect::sink::rest_sink { if (fs::exists(path)) { string root(uri); - if (boost::ends_with(root, "/")) + if (root.ends_with("/")) { boost::erase_last(root, "/"); } diff --git a/src/mtconnect/sink/rest_sink/rest_service.cpp b/src/mtconnect/sink/rest_sink/rest_service.cpp index 46775087c..4bdfbaad2 100644 --- a/src/mtconnect/sink/rest_sink/rest_service.cpp +++ b/src/mtconnect/sink/rest_sink/rest_service.cpp @@ -473,7 +473,7 @@ namespace mtconnect { auto format = request->parameter("format"); auto printer = getPrinter(request->m_accepts, format); - if (device && !ends_with(request->m_path, string("probe")) && + if (device && !request->m_path.ends_with("probe"sv) && m_sinkContract->findDeviceByUUIDorName(*device) == nullptr) return false; @@ -1473,7 +1473,7 @@ namespace mtconnect { { for (const auto &p : m_sinkContract->getPrinters()) { - if (ends_with(accept, p.first)) + if (accept.ends_with(p.first)) return p.first; } } @@ -1616,4 +1616,3 @@ namespace mtconnect { } // namespace sink::rest_sink } // namespace mtconnect - diff --git a/src/mtconnect/sink/rest_sink/server.cpp b/src/mtconnect/sink/rest_sink/server.cpp index 550715817..b05804866 100644 --- a/src/mtconnect/sink/rest_sink/server.cpp +++ b/src/mtconnect/sink/rest_sink/server.cpp @@ -100,7 +100,7 @@ namespace mtconnect::sink::rest_sink { catch (exception &e) { LOG(fatal) << "Cannot start server: " << e.what(); - std::exit(1); + throw FatalException(e.what()); } } diff --git a/src/mtconnect/source/adapter/agent_adapter/agent_adapter.cpp b/src/mtconnect/source/adapter/agent_adapter/agent_adapter.cpp index b99bff088..14fa7124e 100644 --- a/src/mtconnect/source/adapter/agent_adapter/agent_adapter.cpp +++ b/src/mtconnect/source/adapter/agent_adapter/agent_adapter.cpp @@ -125,7 +125,9 @@ namespace mtconnect::source::adapter::agent_adapter { } else if (device || HasOption(m_options, configuration::SourceDevice)) { - m_sourceDevice = GetOption(m_options, configuration::SourceDevice).value_or(*device); + m_sourceDevice = GetOption(m_options, configuration::SourceDevice); + if (!m_sourceDevice) + m_sourceDevice = device; } else { @@ -135,7 +137,7 @@ namespace mtconnect::source::adapter::agent_adapter { m_name = m_url.getUrlText(m_sourceDevice); m_identity = CreateIdentityHash(m_name); - + m_options.insert_or_assign(configuration::AdapterIdentity, m_identity); m_feedbackId = "XmlTransformFeedback:" + m_identity; diff --git a/src/mtconnect/source/adapter/agent_adapter/session_impl.hpp b/src/mtconnect/source/adapter/agent_adapter/session_impl.hpp index 1557d46d3..227ab16fb 100644 --- a/src/mtconnect/source/adapter/agent_adapter/session_impl.hpp +++ b/src/mtconnect/source/adapter/agent_adapter/session_impl.hpp @@ -28,6 +28,7 @@ #include "mtconnect/config.hpp" #include "mtconnect/pipeline/mtconnect_xml_transform.hpp" #include "mtconnect/pipeline/response_document.hpp" +#include "mtconnect/utilities.hpp" #include "session.hpp" namespace mtconnect::source::adapter::agent_adapter { @@ -136,6 +137,10 @@ namespace mtconnect::source::adapter::agent_adapter { if (m_handler && m_handler->m_processData) m_handler->m_processData(data, m_identity); } + catch (FatalException &e) + { + throw e; + } catch (std::system_error &e) { LOG(warning) << "AgentAdapter - Error occurred processing data: " << e.what(); diff --git a/src/mtconnect/source/adapter/mqtt/mqtt_adapter.cpp b/src/mtconnect/source/adapter/mqtt/mqtt_adapter.cpp index 82533ae81..305bab57a 100644 --- a/src/mtconnect/source/adapter/mqtt/mqtt_adapter.cpp +++ b/src/mtconnect/source/adapter/mqtt/mqtt_adapter.cpp @@ -195,9 +195,11 @@ namespace mtconnect { } else if (!HasOption(options, configuration::Topics)) { - LOG(error) << "MQTT Adapter requires at least one topic to subscribe to. Provide 'Topics = " - "' or Topics block"; - exit(1); + stringstream msg; + msg << "MQTT Adapter requires at least one topic to subscribe to. Provide 'Topics = " + "' or Topics block"; + LOG(fatal) << msg.str(); + throw FatalException(msg.str()); } } /// diff --git a/src/mtconnect/source/adapter/shdr/connector.hpp b/src/mtconnect/source/adapter/shdr/connector.hpp index ad0e9ed14..66d4ff3c4 100644 --- a/src/mtconnect/source/adapter/shdr/connector.hpp +++ b/src/mtconnect/source/adapter/shdr/connector.hpp @@ -105,7 +105,7 @@ namespace mtconnect::source::adapter::shdr { void resolved(const boost::system::error_code &error, boost::asio::ip::tcp::resolver::results_type results); void connected(const boost::system::error_code &error, - const boost::asio::ip::tcp::endpoint& endpoint); + const boost::asio::ip::tcp::endpoint &endpoint); void writer(boost::system::error_code ec, std::size_t length); void reader(boost::system::error_code ec, std::size_t length); bool parseSocketBuffer(); diff --git a/src/mtconnect/source/source.cpp b/src/mtconnect/source/source.cpp index d67880b97..97d5ebb83 100644 --- a/src/mtconnect/source/source.cpp +++ b/src/mtconnect/source/source.cpp @@ -15,12 +15,12 @@ // limitations under the License. // -#include - #include "mtconnect/source/source.hpp" #include +#include + #include "mtconnect/logging.hpp" namespace mtconnect::source { @@ -45,18 +45,18 @@ namespace mtconnect::source { std::string CreateIdentityHash(const std::string &input) { using namespace std; - + boost::uuids::detail::sha1 sha1; sha1.process_bytes(input.c_str(), input.length()); boost::uuids::detail::sha1::digest_type digest; sha1.get_digest(digest); - + ostringstream identity; identity << '_' << std::hex; for (int i = 0; i < 5; i++) - identity << (uint16_t) digest[i]; + identity << (uint16_t)digest[i]; return identity.str(); } - + } // namespace mtconnect::source diff --git a/src/mtconnect/source/source.hpp b/src/mtconnect/source/source.hpp index 8ff888bb4..cdef79b11 100644 --- a/src/mtconnect/source/source.hpp +++ b/src/mtconnect/source/source.hpp @@ -95,7 +95,7 @@ namespace mtconnect { std::string m_name; boost::asio::io_context::strand m_strand; }; - + /// @brief create a unique identity hash for an XML id starting with an `_` and 10 hex digits /// @param text the text to create the hashed id /// @returns a string with the hashed result diff --git a/src/mtconnect/utilities.hpp b/src/mtconnect/utilities.hpp index 70bddd58f..8ccbeb09e 100644 --- a/src/mtconnect/utilities.hpp +++ b/src/mtconnect/utilities.hpp @@ -67,6 +67,40 @@ namespace mtconnect { // Message for when enumerations do not exist in an array/enumeration const int ENUM_MISS = -1; + /// @brtief Fatal Error Exception + /// An exception that get thrown to shut down the application. Only caught by the top level worker + /// thread. + class FatalException : public std::exception + { + public: + /// @brief Create a fatal exception with a message + /// @param str The message + FatalException(const std::string &str) : m_what(str) {} + /// @brief Create a fatal exception with a message + /// @param str The message + FatalException(const std::string_view &str) : m_what(str) {} + /// @brief Create a fatal exception with a message + /// @param str The message + FatalException(const char *str) : m_what(str) {} + /// @brief Create a default fatal exception + /// Has the message `Fatal Exception Occurred` + FatalException() : m_what("Fatal Exception Occurred") {} + /// @brief Copy construction from an exception + /// @param ex the exception + FatalException(const std::exception &ex) : m_what(ex.what()) {} + /// @brief Defaut construction + FatalException(const FatalException &) = default; + /// @brief Default destructor + ~FatalException() = default; + + /// @brief gets the message + /// @returns the message as a string + const char *what() const noexcept override { return m_what.c_str(); } + + protected: + std::string m_what; + }; + /// @brief Time formats enum TimeFormat { @@ -224,7 +258,7 @@ namespace mtconnect { #else namespace tzchrono = date; #endif - + switch (format) { case HUM_READ: @@ -330,17 +364,6 @@ namespace mtconnect { /// @return the modified path prefixed AGENT_LIB_API std::string addNamespace(const std::string aPath, const std::string aPrefix); - /// @brief determines of a string ends with an ending - /// @param[in] value the string to check - /// @param[in] ending the ending to verify - /// @return `true` if the string ends with ending - inline bool ends_with(const std::string &value, const std::string_view &ending) - { - if (ending.size() > value.size()) - return false; - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); - } - /// @brief removes white space at the beginning of a string /// @param[in,out] s the string /// @return string with spaces removed @@ -380,17 +403,6 @@ namespace mtconnect { return {key, std::nullopt}; } - /// @brief determines of a string starts with a beginning - /// @param[in] value the string to check - /// @param[in] beginning the beginning to verify - /// @return `true` if the string begins with beginning - inline bool starts_with(const std::string &value, const std::string_view &beginning) - { - if (beginning.size() > value.size()) - return false; - return std::equal(beginning.begin(), beginning.end(), value.begin()); - } - /// @brief Case insensitive equals /// @param a first string /// @param b second string @@ -772,7 +784,7 @@ namespace mtconnect { return ts; } -/// @brief Creates a comparable schema version from a major and minor number + /// @brief Creates a comparable schema version from a major and minor number #define SCHEMA_VERSION(major, minor) (major * 100 + minor) /// @brief Get the default schema version of the agent as a string @@ -819,7 +831,8 @@ namespace mtconnect { /// @param[in] sha the sha1 namespace to use as context /// @param[in] id the id to use transform /// @returns Returns the first 16 characters of the base 64 encoded sha1 - inline std::string makeUniqueId(const ::boost::uuids::detail::sha1 &contextSha, const std::string &id) + inline std::string makeUniqueId(const ::boost::uuids::detail::sha1 &contextSha, + const std::string &id) { using namespace std; using namespace boost::uuids::detail; @@ -833,11 +846,11 @@ namespace mtconnect { }; sha.process_bytes(id.data(), id.length()); - sha1::digest_type digest; + sha1::digest_type digest; sha.get_digest(digest); - auto data = (unsigned int *) digest; - + auto data = (unsigned int *)digest; + string s(32, ' '); auto len = boost::beast::detail::base64::encode(s.data(), data, sizeof(digest)); diff --git a/test_package/agent_test.cpp b/test_package/agent_test.cpp index 2a889c87a..41a60bf69 100644 --- a/test_package/agent_test.cpp +++ b/test_package/agent_test.cpp @@ -63,7 +63,7 @@ class AgentTest : public testing::Test public: typedef std::map map_type; using queue_type = list; - + protected: void SetUp() override { @@ -71,19 +71,19 @@ class AgentTest : public testing::Test m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "1.3", 25, true); m_agentId = to_string(getCurrentTimeInSec()); } - + void TearDown() override { m_agentTestHelper.reset(); } - + void addAdapter(ConfigOptions options = ConfigOptions {}) { m_agentTestHelper->addAdapter(options, "localhost", 7878, m_agentTestHelper->m_agent->getDefaultDevice()->getName()); } - + public: std::string m_agentId; std::unique_ptr m_agentTestHelper; - + std::chrono::milliseconds m_delay {}; }; @@ -91,18 +91,18 @@ TEST_F(AgentTest, Constructor) { using namespace configuration; ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.7"s}}; - + unique_ptr agent = make_unique(m_agentTestHelper->m_ioContext, TEST_RESOURCE_DIR "/samples/badPath.xml", options); auto context = std::make_shared(); context->m_contract = agent->makePipelineContract(); - - ASSERT_THROW(agent->initialize(context), std::runtime_error); + + ASSERT_THROW(agent->initialize(context), FatalException); agent.reset(); - + agent = make_unique(m_agentTestHelper->m_ioContext, TEST_RESOURCE_DIR "/samples/test_config.xml", options); - + context = std::make_shared(); context->m_contract = agent->makePipelineContract(); ASSERT_NO_THROW(agent->initialize(context)); @@ -114,17 +114,17 @@ TEST_F(AgentTest, Probe) PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Devices/m:Device@name", "LinuxCNC"); } - + { PARSE_XML_RESPONSE("/"); ASSERT_XML_PATH_EQUAL(doc, "//m:Devices/m:Device@name", "LinuxCNC"); } - + { PARSE_XML_RESPONSE("/LinuxCNC"); ASSERT_XML_PATH_EQUAL(doc, "//m:Devices/m:Device@name", "LinuxCNC"); } - + { PARSE_XML_RESPONSE("/LinuxCNC/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Devices/m:Device@name", "LinuxCNC"); @@ -135,13 +135,13 @@ TEST_F(AgentTest, FailWithDuplicateDeviceUUID) { using namespace configuration; ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.5"s}}; - + unique_ptr agent = make_unique(m_agentTestHelper->m_ioContext, TEST_RESOURCE_DIR "/samples/dup_uuid.xml", options); auto context = std::make_shared(); context->m_contract = agent->makePipelineContract(); - - ASSERT_THROW(agent->initialize(context), std::runtime_error); + + ASSERT_THROW(agent->initialize(context), FatalException); } TEST_F(AgentTest, should_return_error_for_unknown_device) @@ -159,7 +159,7 @@ TEST_F(AgentTest, should_return_2_6_error_for_unknown_device) { auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + { PARSE_XML_RESPONSE("/LinuxCN/probe"); string message = (string) "Could not find the device 'LinuxCN'"; @@ -180,7 +180,7 @@ TEST_F(AgentTest, should_return_error_when_path_cannot_be_parsed) ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "INVALID_XPATH"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", message.c_str()); } - + { QueryMap query {{"path", "//Axes?//Linear"}}; PARSE_XML_RESPONSE_QUERY("/current", query); @@ -188,7 +188,7 @@ TEST_F(AgentTest, should_return_error_when_path_cannot_be_parsed) ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "INVALID_XPATH"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", message.c_str()); } - + { QueryMap query {{"path", "//Devices/Device[@name=\"I_DON'T_EXIST\""}}; PARSE_XML_RESPONSE_QUERY("/current", query); @@ -203,7 +203,7 @@ TEST_F(AgentTest, should_return_2_6_error_when_path_cannot_be_parsed) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + { QueryMap query {{"path", "//////Linear"}}; PARSE_XML_RESPONSE_QUERY("/current", query); @@ -212,7 +212,7 @@ TEST_F(AgentTest, should_return_2_6_error_when_path_cannot_be_parsed) ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidXPath/m:ErrorMessage", message.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidXPath/m:URI", "/current?path=//////Linear"); } - + { QueryMap query {{"path", "//Axes?//Linear"}}; PARSE_XML_RESPONSE_QUERY("/current", query); @@ -221,7 +221,7 @@ TEST_F(AgentTest, should_return_2_6_error_when_path_cannot_be_parsed) ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidXPath/m:ErrorMessage", message.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidXPath/m:URI", "/current?path=//Axes?//Linear"); } - + { QueryMap query {{"path", "//Devices/Device[@name=\"I_DON'T_EXIST\""}}; PARSE_XML_RESPONSE_QUERY("/current", query); @@ -243,12 +243,12 @@ TEST_F(AgentTest, should_handle_a_correct_path) "UNAVAILABLE"); ASSERT_XML_PATH_COUNT(doc, "//m:ComponentStream", 1); } - + { QueryMap query { - {"path", "//Rotary[@name='C']//DataItem[@category='SAMPLE' or @category='CONDITION']"}}; + {"path", "//Rotary[@name='C']//DataItem[@category='SAMPLE' or @category='CONDITION']"}}; PARSE_XML_RESPONSE_QUERY("/current", query); - + ASSERT_XML_PATH_EQUAL(doc, "//m:ComponentStream[@component='Rotary']//m:SpindleSpeed", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:ComponentStream[@component='Rotary']//m:Load", "UNAVAILABLE"); @@ -266,7 +266,7 @@ TEST_F(AgentTest, should_report_an_invalid_uri) EXPECT_EQ(status::not_found, m_agentTestHelper->session()->m_code); EXPECT_FALSE(m_agentTestHelper->m_dispatched); } - + { PARSE_XML_RESPONSE("/bad/path/"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "INVALID_URI"); @@ -274,7 +274,7 @@ TEST_F(AgentTest, should_report_an_invalid_uri) EXPECT_EQ(status::not_found, m_agentTestHelper->session()->m_code); EXPECT_FALSE(m_agentTestHelper->m_dispatched); } - + { PARSE_XML_RESPONSE("/LinuxCNC/current/blah"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "INVALID_URI"); @@ -288,10 +288,10 @@ TEST_F(AgentTest, should_report_an_invalid_uri) TEST_F(AgentTest, should_report_a_2_6_invalid_uri) { using namespace rest_sink; - + m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + { PARSE_XML_RESPONSE("/bad_path"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI@errorCode", "INVALID_URI"); @@ -301,25 +301,25 @@ TEST_F(AgentTest, should_report_a_2_6_invalid_uri) EXPECT_EQ(status::not_found, m_agentTestHelper->session()->m_code); EXPECT_FALSE(m_agentTestHelper->m_dispatched); } - + { PARSE_XML_RESPONSE("/bad/path/"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI@errorCode", "INVALID_URI"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI/m:ErrorMessage", "0.0.0.0: Cannot find handler for: GET /bad/path/"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI/m:URI", "/bad/path/"); - + EXPECT_EQ(status::not_found, m_agentTestHelper->session()->m_code); EXPECT_FALSE(m_agentTestHelper->m_dispatched); } - + { PARSE_XML_RESPONSE("/LinuxCNC/current/blah"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI@errorCode", "INVALID_URI"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI/m:ErrorMessage", "0.0.0.0: Cannot find handler for: GET /LinuxCNC/current/blah"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI/m:URI", "/LinuxCNC/current/blah"); - + EXPECT_EQ(status::not_found, m_agentTestHelper->session()->m_code); EXPECT_FALSE(m_agentTestHelper->m_dispatched); } @@ -329,21 +329,21 @@ TEST_F(AgentTest, should_handle_current_at) { QueryMap query; PARSE_XML_RESPONSE_QUERY("/current", query); - + addAdapter(); - + // Get the current position auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence(); char line[80] = {0}; - + // Add many events for (int i = 1; i <= 100; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + // Check each current at all the positions. for (int i = 0; i < 100; i++) { @@ -354,7 +354,7 @@ TEST_F(AgentTest, should_handle_current_at) // m_agentTestHelper->printsession(); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line", to_string(i + 1).c_str()); } - + // Test buffer wrapping // Add a large many events for (int i = 101; i <= 301; i++) @@ -362,7 +362,7 @@ TEST_F(AgentTest, should_handle_current_at) sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + // Check each current at all the positions. for (int i = 100; i < 301; i++) { @@ -371,7 +371,7 @@ TEST_F(AgentTest, should_handle_current_at) PARSE_XML_RESPONSE_QUERY("/current", query); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line", to_string(i + 1).c_str()); } - + // Check the first couple of items in the list for (int j = 0; j < 10; j++) { @@ -381,7 +381,7 @@ TEST_F(AgentTest, should_handle_current_at) PARSE_XML_RESPONSE_QUERY("/current", query); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line", to_string(i + 1).c_str()); } - + // Test out of range... { auto i = circ.getSequence() - circ.getBufferSize() - seq - 1; @@ -397,25 +397,25 @@ TEST_F(AgentTest, should_handle_current_at) TEST_F(AgentTest, should_handle_64_bit_current_at) { QueryMap query; - + addAdapter(); - + // Get the current position char line[80] = {0}; - + // Initialize the sliding buffer at a very large number. auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); - + uint64_t start = (((uint64_t)1) << 48) + 1317; circ.setSequence(start); - + // Add many events for (int i = 1; i <= 500; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + // Check each current at all the positions. for (uint64_t i = start + 300; i < start + 500; i++) { @@ -429,22 +429,22 @@ TEST_F(AgentTest, should_handle_64_bit_current_at) TEST_F(AgentTest, should_report_out_of_range_for_current_at) { QueryMap query; - + addAdapter(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 1; i <= 200; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence(); - + { query["at"] = to_string(seq); sprintf(line, "'at' must be less than %d", int32_t(seq)); @@ -452,9 +452,9 @@ TEST_F(AgentTest, should_report_out_of_range_for_current_at) ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", line); } - + seq = circ.getFirstSequence() - 1; - + { query["at"] = to_string(seq); sprintf(line, "'at' must be greater than %d", int32_t(seq)); @@ -468,21 +468,21 @@ TEST_F(AgentTest, should_report_2_6_out_of_range_for_current_at) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + QueryMap query; - + addAdapter(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 1; i <= 200; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence(); auto max = seq - 1; @@ -500,9 +500,9 @@ TEST_F(AgentTest, should_report_2_6_out_of_range_for_current_at) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", "1"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Maximum", to_string(max).c_str()); } - + seq = circ.getFirstSequence() - 1; - + { query["at"] = to_string(seq); sprintf(line, "'at' must be greater than 0"); @@ -523,15 +523,15 @@ TEST_F(AgentTest, AddAdapter) { addAdapter(); } TEST_F(AgentTest, should_download_file) { QueryMap query; - + string uri("/schemas/MTConnectDevices_1.1.xsd"); - + // Register a file with the agent. auto rest = m_agentTestHelper->getRestService(); rest->getFileCache()->setMaxCachedFileSize(100 * 1024); rest->getFileCache()->registerFile( - uri, string(PROJECT_ROOT_DIR "/schemas/MTConnectDevices_1.1.xsd"), "1.1"); - + uri, string(PROJECT_ROOT_DIR "/schemas/MTConnectDevices_1.1.xsd"), "1.1"); + // Reqyest the file... PARSE_TEXT_RESPONSE(uri.c_str()); ASSERT_FALSE(m_agentTestHelper->session()->m_body.empty()); @@ -542,13 +542,13 @@ TEST_F(AgentTest, should_download_file) TEST_F(AgentTest, should_report_not_found_when_cannot_find_file) { QueryMap query; - + string uri("/schemas/MTConnectDevices_1.1.xsd"); - + // Register a file with the agent. auto rest = m_agentTestHelper->getRestService(); rest->getFileCache()->registerFile(uri, string("./BadFileName.xsd"), "1.1"); - + { PARSE_XML_RESPONSE(uri.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:MTConnectError/m:Errors/m:Error@errorCode", "INVALID_URI"); @@ -561,15 +561,15 @@ TEST_F(AgentTest, should_report_2_6_not_found_when_cannot_find_file) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + QueryMap query; - + string uri("/schemas/MTConnectDevices_1.1.xsd"); - + // Register a file with the agent. auto rest = m_agentTestHelper->getRestService(); rest->getFileCache()->registerFile(uri, string("./BadFileName.xsd"), "1.1"); - + { PARSE_XML_RESPONSE(uri.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidURI@errorCode", "INVALID_URI"); @@ -583,20 +583,20 @@ TEST_F(AgentTest, should_include_composition_ids_in_observations) { auto agent = m_agentTestHelper->m_agent.get(); addAdapter(); - + DataItemPtr motor = agent->getDataItemForDevice("LinuxCNC", "zt1"); ASSERT_TRUE(motor); - + DataItemPtr amp = agent->getDataItemForDevice("LinuxCNC", "zt2"); ASSERT_TRUE(amp); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|zt1|100|zt2|200"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Temperature[@dataItemId='zt1']", "100"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Temperature[@dataItemId='zt2']", "200"); - + ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Temperature[@dataItemId='zt1']@compositionId", "zmotor"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Temperature[@dataItemId='zt2']@compositionId", @@ -616,7 +616,7 @@ TEST_F(AgentTest, should_report_an_error_when_the_count_is_out_of_range) "query parameter 'count': cannot convert " "string 'NON_INTEGER' to integer"); } - + { QueryMap query {{"count", "-500"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -625,14 +625,14 @@ TEST_F(AgentTest, should_report_an_error_when_the_count_is_out_of_range) value += to_string(-size); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", value.c_str()); } - + { QueryMap query {{"count", "0"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", "'count' must not be zero(0)"); } - + { QueryMap query {{"count", "500"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -641,7 +641,7 @@ TEST_F(AgentTest, should_report_an_error_when_the_count_is_out_of_range) value += to_string(size); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", value.c_str()); } - + { QueryMap query {{"count", "9999999"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -650,7 +650,7 @@ TEST_F(AgentTest, should_report_an_error_when_the_count_is_out_of_range) value += to_string(size); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", value.c_str()); } - + { QueryMap query {{"count", "-9999999"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -665,7 +665,7 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); int size = circ.getBufferSize() + 1; { @@ -681,7 +681,7 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidParameterValue/m:QueryParameter/m:Type", "integer"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidParameterValue/m:QueryParameter/m:Value", "NON_INTEGER"); } - + { QueryMap query {{"count", "-500"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -698,7 +698,7 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", to_string(-size + 1).c_str()); } - + { QueryMap query {{"count", "0"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); @@ -712,13 +712,13 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", to_string(-size + 1).c_str()); } - + { QueryMap query {{"count", "500"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); string value("'count' must be less than "); value += to_string(size); - + ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:ErrorMessage", value.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:URI", "/sample?count=500"); @@ -729,13 +729,13 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", to_string(-size + 1).c_str()); } - + { QueryMap query {{"count", "9999999"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); string value("'count' must be less than "); value += to_string(size); - + ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:ErrorMessage", value.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:URI", "/sample?count=9999999"); @@ -746,13 +746,13 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", to_string(-size + 1).c_str()); } - + { QueryMap query {{"count", "-9999999"}}; PARSE_XML_RESPONSE_QUERY("/sample", query); string value("'count' must be greater than "); value += to_string(-size); - + ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:ErrorMessage", value.c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:URI", "/sample?count=-9999999"); @@ -768,24 +768,24 @@ TEST_F(AgentTest, should_report_a_2_6_error_when_the_count_is_out_of_range) TEST_F(AgentTest, should_process_addapter_data) { addAdapter(); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[2]", "204"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Alarm[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|alarm|code|nativeCode|severity|state|description"); - + "2021-02-01T12:00:00Z|alarm|code|nativeCode|severity|state|description"); + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -799,17 +799,17 @@ TEST_F(AgentTest, should_get_samples_using_next_sequence) { QueryMap query; addAdapter(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 1; i <= 300; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); } - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence(); { @@ -825,27 +825,27 @@ TEST_F(AgentTest, should_give_correct_number_of_samples_with_count) addAdapter(); auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 0; i < 128; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d|Xact|%d", i, i); m_agentTestHelper->m_adapter->processData(line); } - + { query["path"] = "//DataItem[@name='Xact']"; query["from"] = to_string(seq); query["count"] = "10"; - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + 20).c_str()); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Position", 10); - + // Make sure we got 10 lines for (int j = 0; j < 10; j++) { @@ -859,29 +859,29 @@ TEST_F(AgentTest, should_give_correct_number_of_samples_with_negative_count) { QueryMap query; addAdapter(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 0; i < 128; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d|Xact|%d", i, i); m_agentTestHelper->m_adapter->processData(line); } - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence() - 20; - + { query["path"] = "//DataItem[@name='Xact']"; query["count"] = "-10"; - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq).c_str()); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Position", 10); - + // Make sure we got 10 lines for (int j = 0; j < 10; j++) { @@ -895,30 +895,30 @@ TEST_F(AgentTest, should_give_correct_number_of_samples_with_to_parameter) { QueryMap query; addAdapter(); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 0; i < 128; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d|Xact|%d", i, i); m_agentTestHelper->m_adapter->processData(line); } - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto seq = circ.getSequence() - 20; - + { query["path"] = "//DataItem[@name='Xact']"; query["count"] = "10"; query["to"] = to_string(seq); - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + 1).c_str()); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Position", 10); - + // Make sure we got 10 lines auto start = seq - 20; for (int j = 0; j < 10; j++) @@ -927,18 +927,18 @@ TEST_F(AgentTest, should_give_correct_number_of_samples_with_to_parameter) ASSERT_XML_PATH_EQUAL(doc, line, to_string(start + j * 2 + 1).c_str()); } } - + { query["path"] = "//DataItem[@name='Xact']"; query["count"] = "10"; query["to"] = to_string(seq); query["from"] = to_string(seq - 10); - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + 1).c_str()); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Position", 5); - + // Make sure we got 10 lines auto start = seq - 10; for (int j = 0; j < 5; j++) @@ -947,7 +947,7 @@ TEST_F(AgentTest, should_give_correct_number_of_samples_with_to_parameter) ASSERT_XML_PATH_EQUAL(doc, line, to_string(start + j * 2 + 1).c_str()); } } - + // TODO: Test negative conditions // count < 0 // to > nextSequence @@ -963,11 +963,11 @@ TEST_F(AgentTest, should_give_empty_stream_with_no_new_samples) ASSERT_XML_PATH_EQUAL(doc, "//m:ComponentStream[@componentId='path']/m:Condition/m:Unavailable", nullptr); ASSERT_XML_PATH_EQUAL( - doc, "//m:ComponentStream[@componentId='path']/m:Condition/m:Unavailable@qualifier", - nullptr); + doc, "//m:ComponentStream[@componentId='path']/m:Condition/m:Unavailable@qualifier", + nullptr); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:RotaryMode", "SPINDLE"); } - + { auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); QueryMap query {{"from", to_string(circ.getSequence())}}; @@ -980,31 +980,31 @@ TEST_F(AgentTest, should_not_leak_observations_when_added_to_buffer) { auto agent = m_agentTestHelper->m_agent.get(); QueryMap query; - + string device("LinuxCNC"), key("badKey"), value("ON"); SequenceNumber_t seqNum {0}; auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); auto event1 = circ.getFromBuffer(seqNum); ASSERT_FALSE(event1); - + { query["from"] = to_string(circ.getSequence()); PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Streams", nullptr); } - + key = "power"; - + auto di2 = agent->getDataItemForDevice(device, key); seqNum = m_agentTestHelper->addToBuffer(di2, {{"VALUE", value}}, chrono::system_clock::now()); auto event2 = circ.getFromBuffer(seqNum); ASSERT_EQ(3, event2.use_count()); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PowerState", "ON"); } - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PowerState[1]", "UNAVAILABLE"); @@ -1017,53 +1017,53 @@ TEST_F(AgentTest, should_int_64_sequences_should_not_truncate_at_32_bits) #ifndef WIN32 QueryMap query; addAdapter(); - + // Set the sequence number near MAX_UINT32 auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); circ.setSequence(0xFFFFFFA0); SequenceNumber_t seq = circ.getSequence(); ASSERT_EQ((int64_t)0xFFFFFFA0, seq); - + // Get the current position char line[80] = {0}; - + // Add many events for (int i = 0; i < 128; i++) { sprintf(line, "2021-02-01T12:00:00Z|line|%d", i); m_agentTestHelper->m_adapter->processData(line); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line@sequence", to_string(seq + i).c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + i + 1).c_str()); } - + { query["from"] = to_string(seq); query["count"] = "128"; - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + i + 1).c_str()); - + for (int j = 0; j <= i; j++) { sprintf(line, "//m:DeviceStream//m:Line[%d]@sequence", j + 1); ASSERT_XML_PATH_EQUAL(doc, line, to_string(seq + j).c_str()); } } - + for (int j = 0; j <= i; j++) { query["from"] = to_string(seq + j); query["count"] = "1"; - + PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line@sequence", to_string(seq + j).c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@nextSequence", to_string(seq + j + 1).c_str()); } } - + ASSERT_EQ(uint64_t(0xFFFFFFA0) + 128ul, circ.getSequence()); #endif } @@ -1071,22 +1071,22 @@ TEST_F(AgentTest, should_int_64_sequences_should_not_truncate_at_32_bits) TEST_F(AgentTest, should_not_allow_duplicates_values) { addAdapter(); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[2]", "204"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|205"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -1098,20 +1098,20 @@ TEST_F(AgentTest, should_not_allow_duplicates_values) TEST_F(AgentTest, should_not_duplicate_unavailable_when_disconnected) { addAdapter({{configuration::FilterDuplicates, true}}); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|205"); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[2]", "204"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[3]", "205"); } - + m_agentTestHelper->m_adapter->disconnected(); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -1119,11 +1119,11 @@ TEST_F(AgentTest, should_not_duplicate_unavailable_when_disconnected) ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[3]", "205"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[4]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->connected(); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|205"); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -1143,31 +1143,31 @@ TEST_F(AgentTest, should_handle_auto_available_if_adapter_option_is_set) auto d = agent->getDevices().front(); StringList devices; devices.emplace_back(*d->getComponentName()); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[1]", "UNAVAILABLE"); } - + agent->connected(id, devices, true); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[2]", "AVAILABLE"); } - + agent->disconnected(id, devices, true); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[2]", "AVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[3]", "UNAVAILABLE"); } - + agent->connected(id, devices, true); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Availability[1]", "UNAVAILABLE"); @@ -1183,66 +1183,66 @@ TEST_F(AgentTest, should_handle_multiple_disconnnects) auto agent = m_agentTestHelper->m_agent.get(); auto adapter = m_agentTestHelper->m_adapter; auto id = adapter->getIdentity(); - + auto d = agent->getDevices().front(); StringList devices; devices.emplace_back(*d->getComponentName()); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][1]", "UNAVAILABLE"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Unavailable[@dataItemId='cmp']", 1); } - + agent->connected(id, devices, false); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|block|GTH"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|cmp|normal||||"); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][2]", "GTH"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//*[@dataItemId='p1']", 2); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Unavailable[@dataItemId='cmp']", 1); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Normal[@dataItemId='cmp']", 1); } - + agent->disconnected(id, devices, false); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Unavailable[@dataItemId='cmp']", 2); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Normal[@dataItemId='cmp']", 1); - + ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][2]", "GTH"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][3]", "UNAVAILABLE"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//*[@dataItemId='p1']", 3); } - + agent->disconnected(id, devices, false); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Unavailable[@dataItemId='cmp']", 2); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Normal[@dataItemId='cmp']", 1); - + ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//*[@dataItemId='p1'][3]", "UNAVAILABLE"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//*[@dataItemId='p1']", 3); } - + agent->connected(id, devices, false); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|block|GTH"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|cmp|normal||||"); - + agent->disconnected(id, devices, false); - + { PARSE_XML_RESPONSE("/LinuxCNC/sample"); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Unavailable[@dataItemId='cmp']", 3); ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//m:Normal[@dataItemId='cmp']", 2); - + ASSERT_XML_PATH_COUNT(doc, "//m:DeviceStream//*[@dataItemId='p1']", 5); } } @@ -1250,18 +1250,18 @@ TEST_F(AgentTest, should_handle_multiple_disconnnects) TEST_F(AgentTest, should_ignore_timestamps_if_configured_to_do_so) { addAdapter(); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[2]@timestamp", "2021-02-01T12:00:00Z"); } - + m_agentTestHelper->m_adapter->setOptions({{configuration::IgnoreTimestamps, true}}); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|205"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -1273,7 +1273,7 @@ TEST_F(AgentTest, should_ignore_timestamps_if_configured_to_do_so) TEST_F(AgentTest, InitialTimeSeriesValues) { addAdapter(); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PositionTimeSeries[@dataItemId='x1ts']", @@ -1285,41 +1285,41 @@ TEST_F(AgentTest, should_support_dynamic_calibration_data) { addAdapter({{configuration::ConversionRequired, true}}); auto agent = m_agentTestHelper->getAgent(); - + // Add a 10.111000 seconds m_agentTestHelper->m_adapter->protocolCommand( - "* calibration:Yact|.01|200.0|Zact|0.02|300|Xts|0.01|500"); + "* calibration:Yact|.01|200.0|Zact|0.02|300|Xts|0.01|500"); auto di = agent->getDataItemForDevice("LinuxCNC", "Yact"); ASSERT_TRUE(di); - + // TODO: Fix conversions auto &conv1 = di->getConverter(); ASSERT_TRUE(conv1); ASSERT_EQ(0.01, conv1->factor()); ASSERT_EQ(200.0, conv1->offset()); - + di = agent->getDataItemForDevice("LinuxCNC", "Zact"); ASSERT_TRUE(di); - + auto &conv2 = di->getConverter(); ASSERT_TRUE(conv2); ASSERT_EQ(0.02, conv2->factor()); ASSERT_EQ(300.0, conv2->offset()); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|Yact|200|Zact|600"); m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|Xts|25|| 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 " - "5119 5119 5118 " - "5118 5117 5117 5119 5119 5118 5118 5118 5118 5118"); - + "2021-02-01T12:00:00Z|Xts|25|| 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 5118 " + "5119 5119 5118 " + "5118 5117 5117 5119 5119 5118 5118 5118 5118 5118"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[@dataItemId='y1']", "4"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[@dataItemId='z1']", "18"); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:PositionTimeSeries[@dataItemId='x1ts']", - "56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.19 56.19 56.18 " - "56.18 56.17 56.17 56.19 56.19 56.18 56.18 56.18 56.18 56.18"); + doc, "//m:DeviceStream//m:PositionTimeSeries[@dataItemId='x1ts']", + "56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.18 56.19 56.19 56.18 " + "56.18 56.17 56.17 56.19 56.19 56.18 56.18 56.18 56.18 56.18"); } } @@ -1327,32 +1327,32 @@ TEST_F(AgentTest, should_filter_as_specified_in_1_3_test_1) { m_agentTestHelper->createAgent("/samples/filter_example_1.3.xml", 8, 4, "1.5", 25); addAdapter(); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|load|100"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[2]", "100"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|load|103"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|load|106"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[2]", "100"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[3]", "106"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|load|106|load|108|load|112"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); @@ -1366,15 +1366,15 @@ TEST_F(AgentTest, should_filter_as_specified_in_1_3_test_2) { m_agentTestHelper->createAgent("/samples/filter_example_1.3.xml", 8, 4, "1.5", 25); addAdapter(); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2018-04-27T05:00:26.555666|load|100|pos|20"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); @@ -1382,10 +1382,10 @@ TEST_F(AgentTest, should_filter_as_specified_in_1_3_test_2) ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[2]", "20"); } - + m_agentTestHelper->m_adapter->processData("2018-04-27T05:00:32.000666|load|103|pos|25"); m_agentTestHelper->m_adapter->processData("2018-04-27T05:00:36.888666|load|106|pos|30"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); @@ -1395,10 +1395,10 @@ TEST_F(AgentTest, should_filter_as_specified_in_1_3_test_2) ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[2]", "20"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[3]", "30"); } - + m_agentTestHelper->m_adapter->processData( - "2018-04-27T05:00:40.25|load|106|load|108|load|112|pos|35|pos|40"); - + "2018-04-27T05:00:40.25|load|106|load|108|load|112|pos|35|pos|40"); + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); @@ -1409,9 +1409,9 @@ TEST_F(AgentTest, should_filter_as_specified_in_1_3_test_2) ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[2]", "20"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[3]", "30"); } - + m_agentTestHelper->m_adapter->processData("2018-04-27T05:00:47.50|pos|45|pos|50"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Load[1]", "UNAVAILABLE"); @@ -1431,24 +1431,24 @@ TEST_F(AgentTest, period_filter_should_work_with_ignore_timestamps) // Test period filter with ignore timestamps m_agentTestHelper->createAgent("/samples/filter_example_1.3.xml", 8, 4, "1.5", 25); addAdapter({{configuration::IgnoreTimestamps, true}}); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2018-04-27T05:00:26.555666|load|100|pos|20"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[2]", "20"); } - + m_agentTestHelper->m_adapter->processData("2018-04-27T05:01:32.000666|load|103|pos|25"); this_thread::sleep_for(11s); m_agentTestHelper->m_adapter->processData("2018-04-27T05:01:40.888666|load|106|pos|30"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); @@ -1462,23 +1462,23 @@ TEST_F(AgentTest, period_filter_should_work_with_relative_time) // Test period filter with relative time m_agentTestHelper->createAgent("/samples/filter_example_1.3.xml", 8, 4, "1.5", 25); addAdapter({{configuration::RelativeTime, true}}); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("0|load|100|pos|20"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[2]", "20"); } - + m_agentTestHelper->m_adapter->processData("5000|load|103|pos|25"); m_agentTestHelper->m_adapter->processData("11000|load|106|pos|30"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Position[1]", "UNAVAILABLE"); @@ -1490,13 +1490,13 @@ TEST_F(AgentTest, period_filter_should_work_with_relative_time) TEST_F(AgentTest, reset_triggered_should_work) { addAdapter(); - + m_agentTestHelper->m_adapter->processData("TIME1|pcount|0"); m_agentTestHelper->m_adapter->processData("TIME2|pcount|1"); m_agentTestHelper->m_adapter->processData("TIME3|pcount|2"); m_agentTestHelper->m_adapter->processData("TIME4|pcount|0:DAY"); m_agentTestHelper->m_adapter->processData("TIME3|pcount|5"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PartCount[1]", "UNAVAILABLE"); @@ -1513,58 +1513,58 @@ TEST_F(AgentTest, reset_triggered_should_work) TEST_F(AgentTest, should_honor_references_when_getting_current_or_sample) { using namespace device_model; - + m_agentTestHelper->createAgent("/samples/reference_example.xml"); addAdapter(); auto agent = m_agentTestHelper->getAgent(); - + string id = "mf"; auto item = agent->getDataItemForDevice((string) "LinuxCNC", id); auto comp = item->getComponent(); - + auto references = comp->getList("References"); ASSERT_TRUE(references); ASSERT_EQ(3, references->size()); auto reference = references->begin(); - + EXPECT_EQ("DataItemRef", (*reference)->getName()); - + EXPECT_EQ("chuck", (*reference)->get("name")); EXPECT_EQ("c4", (*reference)->get("idRef")); - + auto ref = dynamic_pointer_cast(*reference); ASSERT_TRUE(ref); - + ASSERT_EQ(Reference::DATA_ITEM, ref->getReferenceType()); ASSERT_TRUE(ref->getDataItem().lock()) << "DataItem was not resolved"; reference++; - + EXPECT_EQ("door", (*reference)->get("name")); EXPECT_EQ("d2", (*reference)->get("idRef")); - + ref = dynamic_pointer_cast(*reference); ASSERT_TRUE(ref); - + ASSERT_EQ(Reference::DATA_ITEM, ref->getReferenceType()); ASSERT_TRUE(ref->getDataItem().lock()) << "DataItem was not resolved"; - + reference++; EXPECT_EQ("electric", (*reference)->get("name")); EXPECT_EQ("ele", (*reference)->get("idRef")); - + ref = dynamic_pointer_cast(*reference); ASSERT_TRUE(ref); - + ASSERT_EQ(Reference::COMPONENT, ref->getReferenceType()); ASSERT_TRUE(ref->getComponent().lock()) << "DataItem was not resolved"; - + // Additional data items should be included { QueryMap query {{"path", "//BarFeederInterface"}}; PARSE_XML_RESPONSE_QUERY("/current", query); - + ASSERT_XML_PATH_EQUAL( - doc, "//m:ComponentStream[@component='BarFeederInterface']//m:MaterialFeed", "UNAVAILABLE"); + doc, "//m:ComponentStream[@component='BarFeederInterface']//m:MaterialFeed", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:ComponentStream[@component='Door']//m:DoorState", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:ComponentStream[@component='Rotary']//m:ChuckState", @@ -1577,34 +1577,34 @@ TEST_F(AgentTest, should_honor_discrete_data_items_and_not_filter_dups) m_agentTestHelper->createAgent("/samples/discrete_example.xml"); addAdapter({{configuration::FilterDuplicates, true}}); auto agent = m_agentTestHelper->getAgent(); - + auto msg = agent->getDataItemForDevice("LinuxCNC", "message"); ASSERT_TRUE(msg); ASSERT_EQ(true, msg->isDiscreteRep()); - + // Validate we are dup checking. { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|205"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[2]", "204"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[3]", "205"); - + ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:MessageDiscrete[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|message|Hi|Hello"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|message|Hi|Hello"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|message|Hi|Hello"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:MessageDiscrete[1]", "UNAVAILABLE"); @@ -1619,17 +1619,17 @@ TEST_F(AgentTest, should_honor_discrete_data_items_and_not_filter_dups) TEST_F(AgentTest, should_honor_upcase_values) { addAdapter({{configuration::FilterDuplicates, true}, {configuration::UpcaseDataItemValue, true}}); - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|mode|Hello"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:ControllerMode", "HELLO"); } - + m_agentTestHelper->m_adapter->setOptions({{configuration::UpcaseDataItemValue, false}}); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|mode|Hello"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:ControllerMode", "Hello"); @@ -1642,7 +1642,7 @@ TEST_F(AgentTest, should_handle_condition_activation) auto agent = m_agentTestHelper->getAgent(); auto logic = agent->getDataItemForDevice("LinuxCNC", "lp"); ASSERT_TRUE(logic); - + // Validate we are dup checking. { PARSE_XML_RESPONSE("/current"); @@ -1652,29 +1652,29 @@ TEST_F(AgentTest, should_handle_condition_activation) "m:Unavailable[@dataItemId='lp']", 1); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|lp|NORMAL||||XXX"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", - "XXX"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", + "XXX"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|lp|FAULT|2218|ALARM_B|HIGH|2218-1 ALARM_B UNUSABLE G-code A side " - "FFFFFFFF"); - + "2021-02-01T12:00:00Z|lp|FAULT|2218|ALARM_B|HIGH|2218-1 ALARM_B UNUSABLE G-code A side " + "FFFFFFFF"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault", - "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault", + "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//" "m:ComponentStream[@component='Controller']/m:Condition/" @@ -1691,28 +1691,28 @@ TEST_F(AgentTest, should_handle_condition_activation) "m:Fault@qualifier", "HIGH"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|lp|NORMAL||||"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", - 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", + 1); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|lp|FAULT|4200|ALARM_D||4200 ALARM_D Power on effective parameter set"); - + "2021-02-01T12:00:00Z|lp|FAULT|4200|ALARM_D||4200 ALARM_D Power on effective parameter set"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault", - "4200 ALARM_D Power on effective parameter set"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault", + "4200 ALARM_D Power on effective parameter set"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//" "m:ComponentStream[@component='Controller']/m:Condition/" @@ -1724,21 +1724,21 @@ TEST_F(AgentTest, should_handle_condition_activation) "m:Fault@nativeSeverity", "ALARM_D"); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|lp|FAULT|2218|ALARM_B|HIGH|2218-1 ALARM_B UNUSABLE G-code A side " - "FFFFFFFF"); - + "2021-02-01T12:00:00Z|lp|FAULT|2218|ALARM_B|HIGH|2218-1 ALARM_B UNUSABLE G-code A side " + "FFFFFFFF"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 2); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 2); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", - "4200 ALARM_D Power on effective parameter set"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", + "4200 ALARM_D Power on effective parameter set"); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[2]", - "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[2]", + "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//" "m:ComponentStream[@component='Controller']/m:Condition/" @@ -1755,18 +1755,18 @@ TEST_F(AgentTest, should_handle_condition_activation) "m:Fault[2]@qualifier", "HIGH"); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|lp|FAULT|4200|ALARM_D|LOW|4200 ALARM_D Power on effective parameter " - "set"); - + "2021-02-01T12:00:00Z|lp|FAULT|4200|ALARM_D|LOW|4200 ALARM_D Power on effective parameter " + "set"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 2); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 2); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", - "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", + "2218-1 ALARM_B UNUSABLE G-code A side FFFFFFFF"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//" "m:ComponentStream[@component='Controller']/m:Condition/" @@ -1783,35 +1783,35 @@ TEST_F(AgentTest, should_handle_condition_activation) "m:Fault[1]@qualifier", "HIGH"); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[2]", - "4200 ALARM_D Power on effective parameter set"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[2]", + "4200 ALARM_D Power on effective parameter set"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|lp|NORMAL|2218|||"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//" "m:ComponentStream[@component='Controller']/m:Condition/" "m:Fault[1]@nativeCode", "4200"); ASSERT_XML_PATH_EQUAL( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", - "4200 ALARM_D Power on effective parameter set"); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Fault[1]", + "4200 ALARM_D Power on effective parameter set"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|lp|NORMAL||||"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/*", 1); ASSERT_XML_PATH_COUNT( - doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", - 1); + doc, "//m:DeviceStream//m:ComponentStream[@component='Controller']/m:Condition/m:Normal", + 1); } } @@ -1819,55 +1819,55 @@ TEST_F(AgentTest, should_handle_empty_entry_as_last_pair_from_adapter) { addAdapter({{configuration::FilterDuplicates, true}}); auto agent = m_agentTestHelper->getAgent(); - + auto program = agent->getDataItemForDevice("LinuxCNC", "program"); ASSERT_TRUE(program); - + auto tool_id = agent->getDataItemForDevice("LinuxCNC", "block"); ASSERT_TRUE(tool_id); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program|A|block|B"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", "A"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", "B"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program||block|B"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", ""); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", "B"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program||block|"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", ""); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", ""); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program|A|block|B"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program|A|block|"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", "A"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", ""); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program|A|block|B|line|C"); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|program|D|block||line|E"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", "D"); @@ -1882,17 +1882,17 @@ TEST_F(AgentTest, should_handle_constant_values) auto agent = m_agentTestHelper->getAgent(); auto di = agent->getDataItemForDevice("LinuxCNC", "block"); ASSERT_TRUE(di); - + di->setConstantValue("UNAVAILABLE"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|block|G01X00|Smode|INDEX|line|204"); - + "2021-02-01T12:00:00Z|block|G01X00|Smode|INDEX|line|204"); + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block[1]", "UNAVAILABLE"); @@ -1906,14 +1906,14 @@ TEST_F(AgentTest, should_handle_constant_values) TEST_F(AgentTest, should_handle_bad_data_item_from_adapter) { addAdapter(); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|bad|ignore|dummy|1244|line|204"); - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Line[1]", "UNAVAILABLE"); @@ -1927,18 +1927,18 @@ TEST_F(AgentTest, adapter_should_receive_commands) { addAdapter(); auto agent = m_agentTestHelper->getAgent(); - + auto device = agent->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); ASSERT_FALSE(device->preserveUuid()); - + m_agentTestHelper->m_adapter->parseBuffer("* uuid: MK-1234\n"); m_agentTestHelper->m_ioContext.run_for(2000ms); - + m_agentTestHelper->m_adapter->parseBuffer("* manufacturer: Big Tool\n"); m_agentTestHelper->m_adapter->parseBuffer("* serialNumber: XXXX-1234\n"); m_agentTestHelper->m_adapter->parseBuffer("* station: YYYY\n"); - + { PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Device@uuid", "MK-1234"); @@ -1946,19 +1946,19 @@ TEST_F(AgentTest, adapter_should_receive_commands) ASSERT_XML_PATH_EQUAL(doc, "//m:Description@serialNumber", "XXXX-1234"); ASSERT_XML_PATH_EQUAL(doc, "//m:Description@station", "YYYY"); } - + device = agent->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); - + device->setPreserveUuid(true); m_agentTestHelper->m_adapter->parseBuffer("* uuid: XXXXXXX\n"); m_agentTestHelper->m_ioContext.run_for(1000ms); - + { PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Device@uuid", "MK-1234"); } - + auto &options = m_agentTestHelper->m_adapter->getOptions(); ASSERT_EQ("MK-1234", *GetOption(options, configuration::Device)); } @@ -1968,21 +1968,21 @@ TEST_F(AgentTest, adapter_should_not_process_uuid_command_with_preserve_uuid) auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.3", 4, false, true, {{configuration::PreserveUUID, true}}); addAdapter(); - + auto device = agent->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); ASSERT_TRUE(device->preserveUuid()); - + m_agentTestHelper->m_adapter->parseBuffer("* uuid: MK-1234\n"); - + { PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Device@uuid", "000"); } - + m_agentTestHelper->m_adapter->processData( - "2021-02-01T12:00:00Z|block|G01X00|mode|AUTOMATIC|execution|READY"); - + "2021-02-01T12:00:00Z|block|G01X00|mode|AUTOMATIC|execution|READY"); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Block", "G01X00"); @@ -1995,37 +1995,37 @@ TEST_F(AgentTest, adapter_should_receive_device_commands) { m_agentTestHelper->createAgent("/samples/two_devices.xml"); auto agent = m_agentTestHelper->getAgent(); - + auto device1 = agent->getDeviceByName("Device1"); ASSERT_TRUE(device1); auto device2 = agent->getDeviceByName("Device2"); ASSERT_TRUE(device2); - + addAdapter(); - + auto device = - GetOption(m_agentTestHelper->m_adapter->getOptions(), configuration::Device); + GetOption(m_agentTestHelper->m_adapter->getOptions(), configuration::Device); ASSERT_EQ(device1->getComponentName(), device); - + m_agentTestHelper->m_adapter->parseBuffer("* device: device-2\n"); device = GetOption(m_agentTestHelper->m_adapter->getOptions(), configuration::Device); ASSERT_EQ(string(*device2->getUuid()), device); - + m_agentTestHelper->m_adapter->parseBuffer("* uuid: new-uuid\n"); - + device2 = agent->getDeviceByName("Device2"); ASSERT_TRUE(device2); - + ASSERT_EQ("new-uuid", string(*device2->getUuid())); - + m_agentTestHelper->m_adapter->parseBuffer("* device: device-1\n"); device = GetOption(m_agentTestHelper->m_adapter->getOptions(), configuration::Device); ASSERT_EQ(string(*device1->getUuid()), device); - + m_agentTestHelper->m_adapter->parseBuffer("* uuid: another-uuid\n"); device1 = agent->getDeviceByName("Device1"); ASSERT_TRUE(device1); - + ASSERT_EQ("another-uuid", string(*device1->getUuid())); } @@ -2033,19 +2033,19 @@ TEST_F(AgentTest, adapter_command_should_set_adapter_and_mtconnect_versions) { m_agentTestHelper->createAgent("/samples/kinematics.xml", 8, 4, "1.7", 25); addAdapter(); - + auto printer = m_agentTestHelper->m_agent->getPrinter("xml"); ASSERT_FALSE(printer->getModelChangeTime().empty()); - + { PARSE_XML_RESPONSE("/Agent/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:AdapterSoftwareVersion", "UNAVAILABLE"); ASSERT_XML_PATH_EQUAL(doc, "//m:MTConnectVersion", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->parseBuffer("* adapterVersion: 2.10\n"); m_agentTestHelper->m_adapter->parseBuffer("* mtconnectVersion: 1.7\n"); - + { PARSE_XML_RESPONSE("/Agent/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:AdapterSoftwareVersion", "2.10"); @@ -2054,24 +2054,24 @@ TEST_F(AgentTest, adapter_command_should_set_adapter_and_mtconnect_versions) printer->getModelChangeTime().c_str()); ; } - + // Test updating device change time string old = printer->getModelChangeTime(); m_agentTestHelper->m_adapter->parseBuffer("* uuid: another-uuid\n"); ASSERT_GT(printer->getModelChangeTime(), old); - + { PARSE_XML_RESPONSE("/Agent/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@deviceModelChangeTime", printer->getModelChangeTime().c_str()); ; } - + // Test Case insensitivity - + m_agentTestHelper->m_adapter->parseBuffer("* adapterversion: 3.10\n"); m_agentTestHelper->m_adapter->parseBuffer("* mtconnectversion: 1.6\n"); - + { PARSE_XML_RESPONSE("/Agent/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:AdapterSoftwareVersion", "3.10"); @@ -2085,14 +2085,14 @@ TEST_F(AgentTest, should_handle_uuid_change) auto device = agent->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); ASSERT_FALSE(device->preserveUuid()); - + addAdapter(); - + m_agentTestHelper->m_adapter->parseBuffer("* uuid: MK-1234\n"); m_agentTestHelper->m_adapter->parseBuffer("* manufacturer: Big Tool\n"); m_agentTestHelper->m_adapter->parseBuffer("* serialNumber: XXXX-1234\n"); m_agentTestHelper->m_adapter->parseBuffer("* station: YYYY\n"); - + { PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Device@uuid", "MK-1234"); @@ -2100,11 +2100,11 @@ TEST_F(AgentTest, should_handle_uuid_change) ASSERT_XML_PATH_EQUAL(doc, "//m:Description@serialNumber", "XXXX-1234"); ASSERT_XML_PATH_EQUAL(doc, "//m:Description@station", "YYYY"); } - + auto *pipe = static_cast(m_agentTestHelper->m_adapter->getPipeline()); - + ASSERT_EQ("MK-1234", pipe->getDevice()); - + { // TODO: Fix and make sure dom is updated so this xpath will parse correctly. // PARSE_XML_RESPONSE("/current?path=//Device[@uuid=\"MK-1234\"]"); @@ -2120,7 +2120,7 @@ TEST_F(AgentTest, should_handle_uuid_change) TEST_F(AgentTest, interval_should_be_a_valid_integer_value) { QueryMap query; - + /// - Cannot be test or a non-integer value { query["interval"] = "NON_INTEGER"; @@ -2130,7 +2130,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value) "query parameter 'interval': cannot " "convert string 'NON_INTEGER' to integer"); } - + /// - Cannot be nagative { query["interval"] = "-123"; @@ -2138,7 +2138,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value) ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", "'interval' must be greater than -1"); } - + /// - Cannot be >= 2147483647 { query["interval"] = "2147483647"; @@ -2146,7 +2146,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value) ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "OUT_OF_RANGE"); ASSERT_XML_PATH_EQUAL(doc, "//m:Error", "'interval' must be less than 2147483647"); } - + /// - Cannot wrap around and create a negative number was set as a int32 { query["interval"] = "999999999999999999"; @@ -2163,7 +2163,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value_in_2_6) m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.6", 4, false, true, {{configuration::Validation, false}}); QueryMap query; - + /// - Cannot be test or a non-integer value { query["interval"] = "NON_INTEGER"; @@ -2178,7 +2178,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value_in_2_6) ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidParameterValue/m:QueryParameter/m:Type", "integer"); ASSERT_XML_PATH_EQUAL(doc, "//m:InvalidParameterValue/m:QueryParameter/m:Value", "NON_INTEGER"); } - + /// - Cannot be nagative { query["interval"] = "-123"; @@ -2192,13 +2192,13 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value_in_2_6) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", "0"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Maximum", "2147483646"); } - + /// - Cannot be >= 2147483647 { query["interval"] = "2147483647"; PARSE_XML_RESPONSE_QUERY("/sample", query); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange@errorCode", "OUT_OF_RANGE"); - + ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:URI", "/sample?interval=2147483647"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:ErrorMessage", "'interval' must be less than 2147483647"); @@ -2207,7 +2207,7 @@ TEST_F(AgentTest, interval_should_be_a_valid_integer_value_in_2_6) ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Minimum", "0"); ASSERT_XML_PATH_EQUAL(doc, "//m:OutOfRange/m:QueryParameter/m:Maximum", "2147483646"); } - + /// - Cannot wrap around and create a negative number was set as a int32 { query["interval"] = "999999999999999999"; @@ -2231,18 +2231,18 @@ TEST_F(AgentTest, should_stream_data_with_interval) auto rest = m_agentTestHelper->getRestService(); auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); rest->start(); - + // Start a thread... QueryMap query; query["interval"] = "50"; query["heartbeat"] = to_string(heartbeatFreq.count()); query["from"] = to_string(circ.getSequence()); - + // Heartbeat test. Heartbeat should be sent in 200ms. Give // 25ms range. { auto slop {35ms}; - + auto startTime = system_clock::now(); PARSE_XML_STREAM_QUERY("/LinuxCNC/sample", query); while (m_agentTestHelper->m_session->m_chunkBody.empty() && @@ -2251,34 +2251,34 @@ TEST_F(AgentTest, should_stream_data_with_interval) auto delta = system_clock::now() - startTime; cout << "Delta after heartbeat: " << delta.count() << endl; ASSERT_FALSE(m_agentTestHelper->m_session->m_chunkBody.empty()); - + PARSE_XML_CHUNK(); ASSERT_XML_PATH_EQUAL(doc, "//m:Streams", nullptr); EXPECT_GT((heartbeatFreq + slop), delta) - << "delta " << delta.count() << " < hbf " << (heartbeatFreq + slop).count(); + << "delta " << delta.count() << " < hbf " << (heartbeatFreq + slop).count(); EXPECT_LT(heartbeatFreq, delta) << "delta > hbf: " << delta.count(); - + m_agentTestHelper->m_session->closeStream(); } - + // Set some data and make sure we get data within 40ms. // Again, allow for some slop. { auto delay {40ms}; auto slop {35ms}; - + PARSE_XML_STREAM_QUERY("/LinuxCNC/sample", query); m_agentTestHelper->m_ioContext.run_for(delay); - + auto startTime = system_clock::now(); m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_ioContext.run_for(5ms); auto delta = system_clock::now() - startTime; cout << "Delta after data: " << delta.count() << endl; - + ASSERT_FALSE(m_agentTestHelper->m_session->m_chunkBody.empty()); PARSE_XML_CHUNK(); - + auto deltaMS = duration_cast(delta); EXPECT_GT(slop, deltaMS) << "delta " << deltaMS.count() << " < delay " << slop.count(); } @@ -2290,9 +2290,9 @@ TEST_F(AgentTest, should_signal_observer_when_observations_arrive) addAdapter(); auto rest = m_agentTestHelper->getRestService(); rest->start(); - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); - + /// - Set up streaming every 100ms with a 1000ms heartbeat std::map query; query["interval"] = "100"; @@ -2300,7 +2300,7 @@ TEST_F(AgentTest, should_signal_observer_when_observations_arrive) query["count"] = "10"; query["from"] = to_string(circ.getSequence()); query["path"] = "//DataItem[@name='line']"; - + /// - Test to make sure the signal will push the sequence number forward and capture /// the new data. { @@ -2312,7 +2312,7 @@ TEST_F(AgentTest, should_signal_observer_when_observations_arrive) } m_agentTestHelper->m_adapter->processData("2021-02-01T12:00:00Z|line|204"); m_agentTestHelper->m_ioContext.run_for(200ms); - + PARSE_XML_CHUNK(); ASSERT_XML_PATH_EQUAL(doc, "//m:Line@sequence", seq.c_str()); } @@ -2324,9 +2324,9 @@ TEST_F(AgentTest, should_fail_if_from_is_out_of_range) addAdapter(); auto rest = m_agentTestHelper->getRestService(); rest->start(); - + auto &circ = m_agentTestHelper->getAgent()->getCircularBuffer(); - + // Start a thread... std::map query; query["interval"] = "100"; @@ -2334,14 +2334,14 @@ TEST_F(AgentTest, should_fail_if_from_is_out_of_range) query["count"] = "10"; query["from"] = to_string(circ.getSequence() + 5); query["path"] = "//DataItem[@name='line']"; - + // Test to make sure the signal will push the sequence number forward and capture // the new data. { PARSE_XML_RESPONSE_QUERY("/LinuxCNC/sample", query); auto seq = to_string(circ.getSequence() + 20ull); m_agentTestHelper->m_ioContext.run_for(200ms); - + ASSERT_XML_PATH_EQUAL(doc, "//m:Error@errorCode", "OUT_OF_RANGE"); } } @@ -2356,18 +2356,18 @@ TEST_F(AgentTest, should_fail_if_from_is_out_of_range) TEST_F(AgentTest, should_allow_making_observations_via_http_put) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "1.3", 4, true); - + QueryMap queries; string body; - + queries["time"] = "2021-02-01T12:00:00Z"; queries["line"] = "205"; queries["power"] = "ON"; - + { PARSE_XML_RESPONSE_PUT("/LinuxCNC", body, queries); } - + { PARSE_XML_RESPONSE("/LinuxCNC/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Line@timestamp", "2021-02-01T12:00:00Z"); @@ -2380,17 +2380,17 @@ TEST_F(AgentTest, should_allow_making_observations_via_http_put) TEST_F(AgentTest, put_condition_should_parse_condition_data) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "1.3", 4, true); - + QueryMap queries; string body; - + queries["time"] = "2021-02-01T12:00:00Z"; queries["lp"] = "FAULT|2001|1||SCANHISTORYRESET"; - + { PARSE_XML_RESPONSE_PUT("/LinuxCNC", body, queries); } - + { PARSE_XML_RESPONSE("/LinuxCNC/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Fault@timestamp", "2021-02-01T12:00:00Z"); @@ -2403,7 +2403,7 @@ TEST_F(AgentTest, put_condition_should_parse_condition_data) TEST_F(AgentTest, shound_add_asset_count_when_20) { m_agentTestHelper->createAgent("/samples/min_config.xml", 8, 4, "2.0", 25); - + { PARSE_XML_RESPONSE("/LinuxCNC/probe"); ASSERT_XML_PATH_COUNT(doc, "//m:DataItem[@type='ASSET_CHANGED']", 1); @@ -2423,7 +2423,7 @@ TEST_F(AgentTest, pre_start_hook_should_be_called) }; m_agentTestHelper->setAgentCreateHook(helperHook); auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true); - + ASSERT_FALSE(called); agent->start(); ASSERT_TRUE(called); @@ -2439,7 +2439,7 @@ TEST_F(AgentTest, pre_initialize_hooks_should_be_called) }; m_agentTestHelper->setAgentCreateHook(helperHook); m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true); - + ASSERT_TRUE(called); } @@ -2452,7 +2452,7 @@ TEST_F(AgentTest, post_initialize_hooks_should_be_called) }; m_agentTestHelper->setAgentCreateHook(helperHook); m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true); - + ASSERT_TRUE(called); } @@ -2465,7 +2465,7 @@ TEST_F(AgentTest, pre_stop_hook_should_be_called) }; m_agentTestHelper->setAgentCreateHook(helperHook); auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true); - + ASSERT_FALSE(called); agent->start(); ASSERT_FALSE(called); @@ -2476,24 +2476,24 @@ TEST_F(AgentTest, pre_stop_hook_should_be_called) TEST_F(AgentTest, device_should_have_hash_for_2_2) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.2", 4, true); - + auto device = m_agentTestHelper->getAgent()->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); - + auto hash = device->get("hash"); ASSERT_EQ(28, hash.length()); - + { PARSE_XML_RESPONSE("/LinuxCNC/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Device@hash", hash.c_str()); } - + auto devices = m_agentTestHelper->getAgent()->getDevices(); auto di = devices.begin(); - + { PARSE_XML_RESPONSE("/Agent/sample"); - + ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceAdded[2]@hash", (*di++)->get("hash").c_str()); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceAdded[3]@hash", (*di)->get("hash").c_str()); } @@ -2502,19 +2502,19 @@ TEST_F(AgentTest, device_should_have_hash_for_2_2) TEST_F(AgentTest, should_not_add_spaces_to_output) { addAdapter(); - + m_agentTestHelper->m_adapter->processData("2024-01-22T20:00:00Z|program|"); m_agentTestHelper->m_adapter->processData("2024-01-22T20:00:00Z|block|"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", ""); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Block", ""); } - + m_agentTestHelper->m_adapter->processData( - "2024-01-22T20:00:00Z|program| |block| "); - + "2024-01-22T20:00:00Z|program| |block| "); + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:Program", ""); @@ -2531,7 +2531,7 @@ TEST_F(AgentTest, should_set_sender_from_config_in_XML_header) PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@sender", "MachineXXX"); } - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@sender", "MachineXXX"); @@ -2547,12 +2547,12 @@ TEST_F(AgentTest, should_not_set_validation_flag_in_header_when_validation_is_fa PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); } - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); } - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); @@ -2568,12 +2568,12 @@ TEST_F(AgentTest, should_set_validation_flag_in_header_when_version_2_5_validati PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", "true"); } - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", "true"); } - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", "true"); @@ -2589,12 +2589,12 @@ TEST_F(AgentTest, should_not_set_validation_flag_in_header_when_version_below_2_ PARSE_XML_RESPONSE("/probe"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); } - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); } - + { PARSE_XML_RESPONSE("/sample"); ASSERT_XML_PATH_EQUAL(doc, "//m:Header@validation", nullptr); @@ -2604,19 +2604,19 @@ TEST_F(AgentTest, should_not_set_validation_flag_in_header_when_version_below_2_ TEST_F(AgentTest, should_initialize_observaton_to_initial_value_when_available) { m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.2", 4, true); - + auto device = m_agentTestHelper->getAgent()->getDeviceByName("LinuxCNC"); ASSERT_TRUE(device); - + addAdapter(); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PartCount", "UNAVAILABLE"); } - + m_agentTestHelper->m_adapter->processData("2024-01-22T20:00:00Z|avail|AVAILABLE"); - + { PARSE_XML_RESPONSE("/current"); ASSERT_XML_PATH_EQUAL(doc, "//m:DeviceStream//m:PartCount", "0"); diff --git a/test_package/agent_test_helper.cpp b/test_package/agent_test_helper.cpp index b2a466a4a..ba25378aa 100644 --- a/test_package/agent_test_helper.cpp +++ b/test_package/agent_test_helper.cpp @@ -75,7 +75,7 @@ void AgentTestHelper::putResponseHelper(const char *file, int line, const string const char *accepts) { makeRequest(file, line, http::verb::put, body, aQueries, path, accepts); - if (ends_with(m_session->m_mimeType, "xml")) + if (m_session->m_mimeType.ends_with("xml"sv)) *doc = xmlParseMemory(m_session->m_body.c_str(), int32_t(m_session->m_body.size())); } @@ -83,7 +83,7 @@ void AgentTestHelper::deleteResponseHelper(const char *file, int line, const Que xmlDocPtr *doc, const char *path, const char *accepts) { makeRequest(file, line, http::verb::delete_, "", aQueries, path, accepts); - if (ends_with(m_session->m_mimeType, "xml")) + if (m_session->m_mimeType.ends_with("xml"sv)) *doc = xmlParseMemory(m_session->m_body.c_str(), int32_t(m_session->m_body.size())); } diff --git a/test_package/file_cache_test.cpp b/test_package/file_cache_test.cpp index a750463fd..48c5db5af 100644 --- a/test_package/file_cache_test.cpp +++ b/test_package/file_cache_test.cpp @@ -107,13 +107,13 @@ TEST_F(FileCacheTest, base_directory_should_redirect) ASSERT_TRUE(file); ASSERT_EQ("/schemas/none.xsd", file->m_redirect); ASSERT_TRUE(m_cache->hasFile("/schemas")); - ASSERT_TRUE(boost::starts_with(std::string(file->m_buffer), "")); + ASSERT_TRUE(std::string_view(file->m_buffer).starts_with("")); auto file2 = m_cache->getFile("/schemas"); ASSERT_TRUE(file); ASSERT_EQ("/schemas/none.xsd", file2->m_redirect); ASSERT_TRUE(m_cache->hasFile("/schemas")); - ASSERT_TRUE(boost::starts_with(std::string(file->m_buffer), "")); + ASSERT_TRUE(std::string_view(file->m_buffer).starts_with("")); } TEST_F(FileCacheTest, file_cache_should_compress_file) diff --git a/test_package/http_server_test.cpp b/test_package/http_server_test.cpp index ff73298c3..81c0a1c56 100644 --- a/test_package/http_server_test.cpp +++ b/test_package/http_server_test.cpp @@ -243,8 +243,9 @@ class Client cout << "spawnRequest: done: false" << endl; m_done = false; m_count = 0; - asio::spawn(m_context, std::bind(&Client::request, this, verb, target, body, close, contentType, - std::placeholders::_1), + asio::spawn(m_context, + std::bind(&Client::request, this, verb, target, body, close, contentType, + std::placeholders::_1), boost::asio::detached); while (!m_done && m_context.run_for(20ms) > 0) @@ -311,8 +312,7 @@ class HttpServerTest : public testing::Test asio::spawn(m_context, std::bind(&Client::connect, m_client.get(), static_cast(m_server->getPort()), std::placeholders::_1), - boost::asio::detached); - + boost::asio::detached); while (!m_client->m_connected) m_context.run_one(); diff --git a/test_package/json_printer_probe_test.cpp b/test_package/json_printer_probe_test.cpp index 1c2a1cb65..2aae84e22 100644 --- a/test_package/json_printer_probe_test.cpp +++ b/test_package/json_printer_probe_test.cpp @@ -362,7 +362,8 @@ TEST_F(JsonPrinterProbeTest, PrintDataItemRelationships) auto dir2 = load.at("/Relationships/1"_json_pointer); ASSERT_TRUE(dir2.is_object()); ASSERT_EQ(string("LIMIT"), dir2.at("/SpecificationRelationship/type"_json_pointer).get()); - ASSERT_EQ(string("spec1"), dir2.at("/SpecificationRelationship/idRef"_json_pointer).get()); + ASSERT_EQ(string("spec1"), + dir2.at("/SpecificationRelationship/idRef"_json_pointer).get()); auto limits = linear.at("/DataItems/5/DataItem"_json_pointer); ASSERT_TRUE(load.is_object()); @@ -371,7 +372,8 @@ TEST_F(JsonPrinterProbeTest, PrintDataItemRelationships) auto dir3 = limits.at("/Relationships/0"_json_pointer); ASSERT_TRUE(dir3.is_object()); ASSERT_EQ(string("bob"), dir3.at("/DataItemRelationship/name"_json_pointer).get()); - ASSERT_EQ(string("OBSERVATION"), dir3.at("/DataItemRelationship/type"_json_pointer).get()); + ASSERT_EQ(string("OBSERVATION"), + dir3.at("/DataItemRelationship/type"_json_pointer).get()); ASSERT_EQ(string("xlc"), dir3.at("/DataItemRelationship/idRef"_json_pointer).get()); } diff --git a/test_package/tls_http_server_test.cpp b/test_package/tls_http_server_test.cpp index 13a047719..262e25081 100644 --- a/test_package/tls_http_server_test.cpp +++ b/test_package/tls_http_server_test.cpp @@ -252,8 +252,10 @@ class Client cout << "spawnRequest: done: false" << endl; m_done = false; m_count = 0; - asio::spawn(m_context, std::bind(&Client::request, this, verb, target, body, close, contentType, - std::placeholders::_1), boost::asio::detached); + asio::spawn(m_context, + std::bind(&Client::request, this, verb, target, body, close, contentType, + std::placeholders::_1), + boost::asio::detached); while (!m_done && !m_failed && m_context.run_for(20ms) > 0) ; diff --git a/test_package/websockets_test.cpp b/test_package/websockets_test.cpp index 07044401f..91b7a0e0f 100644 --- a/test_package/websockets_test.cpp +++ b/test_package/websockets_test.cpp @@ -241,8 +241,9 @@ TEST_F(WebsocketsTest, should_make_simple_request) start(); startClient(); - asio::spawn(m_context, std::bind(&Client::request, m_client.get(), - "{\"id\":\"1\",\"request\":\"probe\"}"s, std::placeholders::_1), + asio::spawn(m_context, + std::bind(&Client::request, m_client.get(), "{\"id\":\"1\",\"request\":\"probe\"}"s, + std::placeholders::_1), boost::asio::detached); m_client->waitFor(2s, [this]() { return m_client->m_done; }); @@ -270,8 +271,9 @@ TEST_F(WebsocketsTest, should_return_error_when_there_is_no_id) start(); startClient(); - asio::spawn(m_context, std::bind(&Client::request, m_client.get(), "{\"request\":\"probe\"}"s, - std::placeholders::_1), + asio::spawn(m_context, + std::bind(&Client::request, m_client.get(), "{\"request\":\"probe\"}"s, + std::placeholders::_1), boost::asio::detached); m_client->waitFor(2s, [this]() { return m_client->m_done; }); @@ -362,8 +364,7 @@ TEST_F(WebsocketsTest, should_return_error_when_bad_json_is_sent) start(); startClient(); - asio::spawn(m_context, - std::bind(&Client::request, m_client.get(), "!}}"s, std::placeholders::_1), + asio::spawn(m_context, std::bind(&Client::request, m_client.get(), "!}}"s, std::placeholders::_1), boost::asio::detached); m_client->waitFor(2s, [this]() { return m_client->m_done; }); @@ -399,7 +400,7 @@ TEST_F(WebsocketsTest, should_return_multiple_errors_when_parameters_are_invalid std::bind(&Client::request, m_client.get(), R"DOC({"id": 3, "request": "sample", "interval": 99999999999,"to": -1 })DOC", std::placeholders::_1), - boost::asio::detached); + boost::asio::detached); m_client->waitFor(2s, [this]() { return m_client->m_done; }); diff --git a/test_package/xml_parser_test.cpp b/test_package/xml_parser_test.cpp index 88e61545a..f2735bead 100644 --- a/test_package/xml_parser_test.cpp +++ b/test_package/xml_parser_test.cpp @@ -87,7 +87,7 @@ TEST_F(XmlParserTest, Constructor) std::unique_ptr printer(new printer::XmlPrinter()); m_xmlParser = new parser::XmlParser(); ASSERT_THROW(m_xmlParser->parseFile(TEST_RESOURCE_DIR "/samples/badPath.xml", printer.get()), - std::runtime_error); + FatalException); delete m_xmlParser; m_xmlParser = nullptr; m_xmlParser = new parser::XmlParser();