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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/mtconnect/agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,14 @@ namespace mtconnect {
{
auto printer = dynamic_cast<printer::XmlPrinter *>(m_printers["xml"].get());
auto device = m_xmlParser->parseDevice(deviceXml, printer);
loadDevices({device}, source);
if (device == nullptr)
{
LOG(error) << "Error loading device: " << deviceXml;
}
else
{
loadDevices({device}, source);
}
}
catch (runtime_error &e)
{
Expand Down
3 changes: 2 additions & 1 deletion src/mtconnect/configuration/agent_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ namespace mtconnect::configuration {
}

ptree empty;
auto logger = config.get_child_optional("logger_config").value_or(empty);
auto logger = config.get_child_optional("logger_config")
.value_or(config.get_child_optional("logging").value_or(empty));

const string defaultFileName = channelName + ".log";
const string defaultArchivePattern = channelName + "_%Y-%m-%d_%H-%M-%S_%N.log";
Expand Down
80 changes: 67 additions & 13 deletions src/mtconnect/parser/xml_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,33 +258,87 @@ namespace mtconnect::parser {
DevicePtr XmlParser::parseDevice(const std::string &deviceXml, printer::XmlPrinter *aPrinter)
{
DevicePtr device;

using namespace boost::adaptors;
using namespace boost::range;

std::unique_lock lock(m_mutex);

// Parse the device XML unti an in memory doc and then see if we have a root MTConnectDevices
// node or a Device node. If devices, then we need to find the first device and then use the
// entity parser to parse the device. We then log any errors.

xmlDocPtr doc = nullptr;
try
{
entity::ErrorList errors;
auto entity = entity::XmlParser::parse(Device::getRoot(), deviceXml, errors);
if (errors.size() > 0)
xmlInitParser();
xmlSetGenericErrorFunc(nullptr, agentXMLErrorFunc);

doc = xmlReadMemory(deviceXml.c_str(), int32_t(deviceXml.length()), "DeviceStream.xml",
nullptr, XML_PARSE_NOBLANKS);
if (!doc)
throw runtime_error("Failed to parse device XML");

auto root = xmlDocGetRootElement(doc);
if (!root)
throw runtime_error("Device XML has no root element");

xmlNodePtr deviceNode = nullptr;
if (xmlStrcmp(root->name, BAD_CAST "MTConnectDevices") == 0)
{
LOG(warning) << "Errors parsing Device: " << deviceXml;
for (auto &e : errors)
for (auto child = root->children; child; child = child->next)
{
LOG(warning) << " " << e->what();
if (xmlStrcmp(child->name, BAD_CAST "Devices") == 0)
{
deviceNode = child->children;
break;
}
}
}
else if (xmlStrcmp(root->name, BAD_CAST "Device") == 0)
{
deviceNode = root;
}
else
{
device = dynamic_pointer_cast<Device>(entity);
throw runtime_error("Root element of device XML must be either MTConnectDevices or Device");
}

if (!deviceNode)
throw runtime_error("No Device node found in device XML");

entity::ErrorList errors;
auto entity = entity::XmlParser::parseXmlNode(Device::getRoot(), deviceNode, errors);

for (auto &e : errors)
{
if (entity)
LOG(warning) << "When parsing device, a problem was skipped: " << e->what();
else
LOG(error) << "Failed to parse device: " << e->what();
}

if (entity)
device = dynamic_pointer_cast<Device>(entity);
else
LOG(error) << "Failed to parse device, skipping";

xmlFreeDoc(doc);
doc = nullptr;
}
catch (const runtime_error &e)
{
if (doc)
xmlFreeDoc(doc);
LOG(error) << "Cannot parse device XML: " << e.what();
}
catch (const string &e)
{
LOG(fatal) << "Cannot parse XML document: " << e;
throw FatalException();
if (doc)
xmlFreeDoc(doc);
LOG(error) << "Cannot parse XML document: " << e;
}
catch (...)
{
if (doc)
xmlFreeDoc(doc);
LOG(error) << "Cannot parse XML document: unknown exception";
}

return device;
Expand Down
1 change: 1 addition & 0 deletions src/mtconnect/sink/rest_sink/request.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace mtconnect::sink::rest_sink {
std::string m_contentType; ///< The content type for the body
std::string m_path; ///< The URI for the request
std::string m_foreignIp; ///< The requestors IP Address
std::string m_foreignHost; ///< The requestors IP Address
uint16_t m_foreignPort; ///< The requestors Port
QueryMap m_query; ///< The parsed query parameters
ParameterMap m_parameters; ///< The parsed path parameters
Expand Down
6 changes: 6 additions & 0 deletions src/mtconnect/sink/rest_sink/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ namespace mtconnect::sink::rest_sink {
fail(ec, "Cannot open server socket");
return;
}
if (m_address.is_v6())
{
// Enable dual-stack by default. It will allow 0.0.0.0 if ::
m_acceptor.set_option(boost::asio::ip::v6_only(false), ec);
ec = {}; // not fatal if unsupported
}
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec);
if (ec)
{
Expand Down
5 changes: 3 additions & 2 deletions src/mtconnect/sink/rest_sink/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace mtconnect::sink::rest_sink {
/// @param options configuration options
/// - Port, defaults to 5000
/// - AllowPut, defaults to false
/// - ServerIp, defaults to 0.0.0.0
/// - ServerIp, defaults to ::
/// - HttpHeaders
Server(boost::asio::io_context &context, const ConfigOptions &options = {})
: m_context(context),
Expand All @@ -65,7 +65,7 @@ namespace mtconnect::sink::rest_sink {
auto inter = GetOption<std::string>(options, configuration::ServerIp);
if (!inter)
{
m_address = boost::asio::ip::make_address("0.0.0.0");
m_address = boost::asio::ip::make_address("::");
}
else
{
Expand Down Expand Up @@ -201,6 +201,7 @@ namespace mtconnect::sink::rest_sink {
RestError re(error, request->m_accepts, status::not_found, std::nullopt,
request->m_requestId);
re.setUri(request->getUri());
LOG(warning) << "[" << request->m_foreignHost << "]: " << txt.str();
m_errorFunction(session, re);
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/mtconnect/sink/rest_sink/session_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,17 @@ namespace mtconnect::sink::rest_sink {
}

m_request->m_foreignIp = remote.address().to_string();
if (auto a = msg.find(http::field::forwarded); a != msg.end())
m_request->m_foreignHost = string(a->value());
else if (auto a = msg.find(http::field::host); a != msg.end())
m_request->m_foreignHost = string(a->value());
else
m_request->m_foreignHost = m_request->m_foreignIp;
m_request->m_foreignPort = remote.port();
if (auto a = msg.find(http::field::connection); a != msg.end())
m_close = a->value() == "close";

LOG(info) << "ReST Request: From [" << m_request->m_foreignIp << ':' << remote.port()
LOG(info) << "ReST Request: From [" << m_request->m_foreignHost << ':' << remote.port()
<< "]: " << msg.method() << " " << msg.target();

// Check if this is a websocket upgrade request. If so, begin a websocket session.
Expand Down Expand Up @@ -302,7 +308,7 @@ namespace mtconnect::sink::rest_sink {
m_complete = complete;
m_mimeType = mimeType;
m_streaming = true;

auto now = std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::now());
std::string date = std::format("{:%a, %d %b %Y %T} GMT", now);

Expand Down
10 changes: 5 additions & 5 deletions test_package/agent_asset_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ TEST_F(AgentAssetTest, should_add_asset_changed_and_asset_added_with_discrete_in
}
}

TEST_F(AgentAssetTest, AssetPrependId)
TEST_F(AgentAssetTest, asset_id_is_zero_padded_when_prepend_id_prefix_is_used)
{
addAdapter();
auto agent = m_agentTestHelper->getAgent();
Expand Down Expand Up @@ -957,7 +957,7 @@ TEST_F(AgentAssetTest, should_respond_to_http_push_with_list_of_errors)
}
}

TEST_F(AgentAssetTest, update_asset_count_data_item_v2_0)
TEST_F(AgentAssetTest, asset_count_data_set_is_updated_when_assets_are_added_or_removed)
{
m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 10, "2.0", 4, true);
addAdapter();
Expand Down Expand Up @@ -1031,7 +1031,7 @@ TEST_F(AgentAssetTest, update_asset_count_data_item_v2_0)
}
}

TEST_F(AgentAssetTest, asset_count_should_not_occur_in_header_post_20)
TEST_F(AgentAssetTest, asset_count_is_absent_from_probe_header_in_schema_2_0)
{
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);

Expand All @@ -1057,7 +1057,7 @@ TEST_F(AgentAssetTest, asset_count_should_not_occur_in_header_post_20)
}
}

TEST_F(AgentAssetTest, asset_count_should_track_asset_additions_by_type)
TEST_F(AgentAssetTest, asset_count_tracks_additions_and_removals_per_type)
{
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);

Expand Down Expand Up @@ -1115,7 +1115,7 @@ TEST_F(AgentAssetTest, asset_count_should_track_asset_additions_by_type)
}
}

TEST_F(AgentAssetTest, asset_should_also_work_using_post_with_assets)
TEST_F(AgentAssetTest, assets_endpoint_accepts_post_requests_for_asset_storage)
{
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);

Expand Down
12 changes: 6 additions & 6 deletions test_package/agent_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class AgentTest : public testing::Test
std::chrono::milliseconds m_delay {};
};

TEST_F(AgentTest, Constructor)
TEST_F(AgentTest, agent_throws_fatal_exception_for_bad_path_and_initializes_with_valid_path)
{
using namespace configuration;
ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.7"s}};
Expand All @@ -109,7 +109,7 @@ TEST_F(AgentTest, Constructor)
ASSERT_NO_THROW(agent->initialize(context));
}

TEST_F(AgentTest, Probe)
TEST_F(AgentTest, probe_endpoint_returns_device_name_for_multiple_paths)
{
{
PARSE_XML_RESPONSE("/probe");
Expand All @@ -132,7 +132,7 @@ TEST_F(AgentTest, Probe)
}
}

TEST_F(AgentTest, FailWithDuplicateDeviceUUID)
TEST_F(AgentTest, agent_throws_fatal_exception_when_devices_have_duplicate_uuid)
{
using namespace configuration;
ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.5"s}};
Expand Down Expand Up @@ -519,7 +519,7 @@ TEST_F(AgentTest, should_report_2_6_out_of_range_for_current_at)
}
}

TEST_F(AgentTest, AddAdapter) { addAdapter(); }
TEST_F(AgentTest, adapter_can_be_added_to_agent) { addAdapter(); }

TEST_F(AgentTest, should_download_file)
{
Expand Down Expand Up @@ -1271,7 +1271,7 @@ TEST_F(AgentTest, should_ignore_timestamps_if_configured_to_do_so)
}
}

TEST_F(AgentTest, InitialTimeSeriesValues)
TEST_F(AgentTest, time_series_data_item_reports_unavailable_initially)
{
addAdapter();

Expand Down Expand Up @@ -2401,7 +2401,7 @@ TEST_F(AgentTest, put_condition_should_parse_condition_data)
}
}

TEST_F(AgentTest, shound_add_asset_count_when_20)
TEST_F(AgentTest, asset_count_data_item_is_added_to_probe_in_schema_2_0)
{
m_agentTestHelper->createAgent("/samples/min_config.xml", 8, 4, "2.0", 25);

Expand Down
8 changes: 4 additions & 4 deletions test_package/asset_buffer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class AssetBufferTest : public testing::Test
std::unique_ptr<AssetBuffer> m_assetBuffer;
};

TEST_F(AssetBufferTest, AddAsset)
TEST_F(AssetBufferTest, asset_is_added_to_buffer)
{
ErrorList errors;
auto asset = makeAsset("Asset", "A1", "D1", "2020-12-01T12:00:00Z", errors);
Expand All @@ -128,7 +128,7 @@ TEST_F(AssetBufferTest, AddAsset)
ASSERT_EQ(1, m_assetBuffer->getCountForDevice("D1"));
}

TEST_F(AssetBufferTest, ReplaceAsset)
TEST_F(AssetBufferTest, existing_asset_is_replaced_in_buffer)
{
ErrorList errors;
auto asset1 = makeAsset("Asset", "A1", "D1", "2020-12-01T12:00:00Z", errors);
Expand All @@ -147,7 +147,7 @@ TEST_F(AssetBufferTest, ReplaceAsset)
ASSERT_EQ(1, m_assetBuffer->getCountForDevice("D2"));
}

TEST_F(AssetBufferTest, TestOverflow)
TEST_F(AssetBufferTest, oldest_asset_is_evicted_when_buffer_overflows)
{
ErrorList errors;
for (int i = 0; i < 10; i++)
Expand Down Expand Up @@ -175,7 +175,7 @@ TEST_F(AssetBufferTest, TestOverflow)
ASSERT_EQ(1, m_assetBuffer->getCountForDevice("D3"));
}

TEST_F(AssetBufferTest, RemovedAsset)
TEST_F(AssetBufferTest, removed_asset_decrements_count_and_is_evicted_on_overflow)
{
ErrorList errors;
for (int i = 0; i < 10; i++)
Expand Down
2 changes: 1 addition & 1 deletion test_package/asset_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class AssetTest : public testing::Test
std::unique_ptr<printer::XmlWriter> m_writer;
};

TEST_F(AssetTest, TestExtendedAsset)
TEST_F(AssetTest, extended_asset_with_arbitrary_content_is_parsed_and_printed)
{
auto doc =
R"DOC(<ExtendedAsset assetId="EXT1" deviceUuid="local" timestamp="2020-12-20T12:00:00Z">
Expand Down
10 changes: 5 additions & 5 deletions test_package/change_observer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ namespace mtconnect {
std::optional<WorkGuard> m_guard;
};

TEST_F(ChangeObserverTest, AddObserver)
TEST_F(ChangeObserverTest, observer_is_registered_with_signaler_after_add)
{
mtconnect::ChangeObserver changeObserver(*m_strand);

Expand All @@ -81,7 +81,7 @@ namespace mtconnect {
ASSERT_TRUE(m_signaler->hasObserver(&changeObserver));
}

TEST_F(ChangeObserverTest, SignalObserver)
TEST_F(ChangeObserverTest, observer_receives_signal_with_correct_sequence_number)
{
mtconnect::ChangeObserver changeObserver(*m_strand);

Expand Down Expand Up @@ -139,7 +139,7 @@ namespace mtconnect {
ASSERT_FALSE(changeObserver.wasSignaled());
}

TEST_F(ChangeObserverTest, Cleanup)
TEST_F(ChangeObserverTest, observer_is_removed_from_signaler_when_destroyed)
{
mtconnect::ChangeObserver *changeObserver = nullptr;

Expand All @@ -153,7 +153,7 @@ namespace mtconnect {
ASSERT_FALSE(m_signaler->hasObserver(changeObserver));
}

TEST_F(ChangeObserverTest, ChangeSequence)
TEST_F(ChangeObserverTest, observer_captures_lowest_sequence_when_signaled_multiple_times)
{
mtconnect::ChangeObserver changeObserver(*m_strand);

Expand Down Expand Up @@ -183,7 +183,7 @@ namespace mtconnect {
ASSERT_EQ(uint64_t {100}, changeObserver.getSequence());
}

TEST_F(ChangeObserverTest, ChangeSequence2)
TEST_F(ChangeObserverTest, observer_tracks_minimum_sequence_across_out_of_order_signals)
{
using namespace std::chrono_literals;
mtconnect::ChangeObserver changeObserver(*m_strand);
Expand Down
Loading
Loading