Cleanup shm at startup in message_bridge_test
When we start forwarding messages from before connection, we need shm to
be clean. Take this oppertunity to dedup some things.
Change-Id: Ic4caff28ba63e48ce5e74a28868deb5c808a984d
diff --git a/WORKSPACE b/WORKSPACE
index bcdbf4f..6c9949d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -169,6 +169,7 @@
http_archive(
name = "arm_frc_linux_gnueabi_repo",
build_file = "@//tools/cpp/arm-frc-linux-gnueabi:arm-frc-linux-gnueabi.BUILD",
+ patches = ["//debian:fts.patch"],
sha256 = "043a5b047c2af9cf80d146d8327b588264c98a01e0f3f41e3564dd2bbbc95c0e",
strip_prefix = "frc2020/roborio/",
url = "https://www.frc971.org/Build-Dependencies/FRC-2020-Linux-Toolchain-7.3.0.tar.gz",
diff --git a/aos/network/BUILD b/aos/network/BUILD
index 98a271c..b142967 100644
--- a/aos/network/BUILD
+++ b/aos/network/BUILD
@@ -299,7 +299,7 @@
":message_bridge_test_client_config",
":message_bridge_test_server_config",
],
- shard_count = 3,
+ shard_count = 4,
deps = [
":message_bridge_client_lib",
":message_bridge_server_lib",
diff --git a/aos/network/message_bridge_test.cc b/aos/network/message_bridge_test.cc
index aa0a034..a3e7f63 100644
--- a/aos/network/message_bridge_test.cc
+++ b/aos/network/message_bridge_test.cc
@@ -9,6 +9,7 @@
#include "aos/network/message_bridge_client_lib.h"
#include "aos/network/message_bridge_server_lib.h"
#include "aos/network/team_number.h"
+#include "aos/util/file.h"
namespace aos {
void SetShmBase(const std::string_view base);
@@ -18,17 +19,36 @@
namespace chrono = std::chrono;
-void DoSetShmBase(const std::string_view node) {
+std::string ShmBase(const std::string_view node) {
const char *tmpdir_c_str = getenv("TEST_TMPDIR");
if (tmpdir_c_str != nullptr) {
- aos::SetShmBase(absl::StrCat(tmpdir_c_str, "/", node));
+ return absl::StrCat(tmpdir_c_str, "/", node);
} else {
- aos::SetShmBase(absl::StrCat("/dev/shm/", node));
+ return absl::StrCat("/dev/shm/", node);
}
}
+void DoSetShmBase(const std::string_view node) {
+ aos::SetShmBase(ShmBase(node));
+}
+
+class MessageBridgeTest : public ::testing::Test {
+ public:
+ MessageBridgeTest()
+ : pi1_config(aos::configuration::ReadConfig(
+ "aos/network/message_bridge_test_server_config.json")),
+ pi2_config(aos::configuration::ReadConfig(
+ "aos/network/message_bridge_test_client_config.json")) {
+ util::UnlinkRecursive(ShmBase("pi1"));
+ util::UnlinkRecursive(ShmBase("pi2"));
+ }
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> pi1_config;
+ aos::FlatbufferDetachedBuffer<aos::Configuration> pi2_config;
+};
+
// Test that we can send a ping message over sctp and receive it.
-TEST(MessageBridgeTest, PingPong) {
+TEST_F(MessageBridgeTest, PingPong) {
// This is rather annoying to set up. We need to start up a client and
// server, on the same node, but get them to think that they are on different
// nodes.
@@ -49,32 +69,25 @@
// hope for the best. We can be more generous in the future if we need to.
//
// We are faking the application names by passing in --application_name=foo
- aos::FlatbufferDetachedBuffer<aos::Configuration> server_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_server_config.json");
- aos::FlatbufferDetachedBuffer<aos::Configuration> pi2_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_client_config.json");
-
DoSetShmBase("pi1");
FLAGS_application_name = "pi1_message_bridge_server";
// Force ourselves to be "raspberrypi" and allocate everything.
FLAGS_override_hostname = "raspberrypi";
- aos::ShmEventLoop pi1_server_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_server_event_loop(&pi1_config.message());
MessageBridgeServer pi1_message_bridge_server(&pi1_server_event_loop);
FLAGS_application_name = "pi1_message_bridge_client";
- aos::ShmEventLoop pi1_client_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_client_event_loop(&pi1_config.message());
MessageBridgeClient pi1_message_bridge_client(&pi1_client_event_loop);
// And build the app which sends the pings.
FLAGS_application_name = "ping";
- aos::ShmEventLoop ping_event_loop(&server_config.message());
+ aos::ShmEventLoop ping_event_loop(&pi1_config.message());
aos::Sender<examples::Ping> ping_sender =
ping_event_loop.MakeSender<examples::Ping>("/test");
- aos::ShmEventLoop pi1_test_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_test_event_loop(&pi1_config.message());
aos::Fetcher<logger::MessageHeader> message_header_fetcher1 =
pi1_test_event_loop.MakeFetcher<logger::MessageHeader>(
"/pi1/aos/remote_timestamps/pi2");
@@ -399,7 +412,7 @@
// Test that the client disconnecting triggers the server offsets on both sides
// to clear.
-TEST(MessageBridgeTest, ClientRestart) {
+TEST_F(MessageBridgeTest, ClientRestart) {
// This is rather annoying to set up. We need to start up a client and
// server, on the same node, but get them to think that they are on different
// nodes.
@@ -414,27 +427,20 @@
// hope for the best. We can be more generous in the future if we need to.
//
// We are faking the application names by passing in --application_name=foo
- aos::FlatbufferDetachedBuffer<aos::Configuration> server_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_server_config.json");
- aos::FlatbufferDetachedBuffer<aos::Configuration> pi2_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_client_config.json");
-
FLAGS_application_name = "pi1_message_bridge_server";
// Force ourselves to be "raspberrypi" and allocate everything.
FLAGS_override_hostname = "raspberrypi";
DoSetShmBase("pi1");
- aos::ShmEventLoop pi1_server_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_server_event_loop(&pi1_config.message());
MessageBridgeServer pi1_message_bridge_server(&pi1_server_event_loop);
FLAGS_application_name = "pi1_message_bridge_client";
- aos::ShmEventLoop pi1_client_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_client_event_loop(&pi1_config.message());
MessageBridgeClient pi1_message_bridge_client(&pi1_client_event_loop);
// And build the app for testing.
FLAGS_application_name = "test1";
- aos::ShmEventLoop pi1_test_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_test_event_loop(&pi1_config.message());
aos::Fetcher<ServerStatistics> pi1_server_statistics_fetcher =
pi1_test_event_loop.MakeFetcher<ServerStatistics>("/pi1/aos");
@@ -607,7 +613,7 @@
// Test that the server disconnecting triggers the server offsets on the other
// side to clear, along with the other client.
-TEST(MessageBridgeTest, ServerRestart) {
+TEST_F(MessageBridgeTest, ServerRestart) {
// This is rather annoying to set up. We need to start up a client and
// server, on the same node, but get them to think that they are on different
// nodes.
@@ -622,27 +628,20 @@
// hope for the best. We can be more generous in the future if we need to.
//
// We are faking the application names by passing in --application_name=foo
- aos::FlatbufferDetachedBuffer<aos::Configuration> server_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_server_config.json");
- aos::FlatbufferDetachedBuffer<aos::Configuration> pi2_config =
- aos::configuration::ReadConfig(
- "aos/network/message_bridge_test_client_config.json");
-
FLAGS_application_name = "pi1_message_bridge_server";
// Force ourselves to be "raspberrypi" and allocate everything.
FLAGS_override_hostname = "raspberrypi";
DoSetShmBase("pi1");
- aos::ShmEventLoop pi1_server_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_server_event_loop(&pi1_config.message());
MessageBridgeServer pi1_message_bridge_server(&pi1_server_event_loop);
FLAGS_application_name = "pi1_message_bridge_client";
- aos::ShmEventLoop pi1_client_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_client_event_loop(&pi1_config.message());
MessageBridgeClient pi1_message_bridge_client(&pi1_client_event_loop);
// And build the app for testing.
FLAGS_application_name = "test1";
- aos::ShmEventLoop pi1_test_event_loop(&server_config.message());
+ aos::ShmEventLoop pi1_test_event_loop(&pi1_config.message());
aos::Fetcher<ServerStatistics> pi1_server_statistics_fetcher =
pi1_test_event_loop.MakeFetcher<ServerStatistics>("/pi1/aos");
aos::Fetcher<ClientStatistics> pi1_client_statistics_fetcher =
diff --git a/aos/util/file.cc b/aos/util/file.cc
index afefa86..97500d1 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -1,6 +1,7 @@
#include "aos/util/file.h"
#include <fcntl.h>
+#include <fts.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -78,5 +79,64 @@
return stat(path.data(), &buffer) == 0;
}
+void UnlinkRecursive(std::string_view path) {
+ FTS *ftsp = NULL;
+ FTSENT *curr;
+
+ // Cast needed (in C) because fts_open() takes a "char * const *", instead
+ // of a "const char * const *", which is only allowed in C++. fts_open()
+ // does not modify the argument.
+ std::string p(path);
+ char *files[] = {const_cast<char *>(p.c_str()), NULL};
+
+ // FTS_NOCHDIR - Avoid changing cwd, which could cause unexpected behavior
+ // in multithreaded programs
+ // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
+ // of the specified directory
+ // FTS_XDEV - Don't cross filesystem boundaries
+ ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
+ if (!ftsp) {
+ return;
+ }
+
+ while ((curr = fts_read(ftsp))) {
+ switch (curr->fts_info) {
+ case FTS_NS:
+ case FTS_DNR:
+ case FTS_ERR:
+ LOG(WARNING) << "Can't read " << curr->fts_accpath;
+ break;
+
+ case FTS_DC:
+ case FTS_DOT:
+ case FTS_NSOK:
+ // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
+ // passed to fts_open()
+ break;
+
+ case FTS_D:
+ // Do nothing. Need depth-first search, so directories are deleted
+ // in FTS_DP
+ break;
+
+ case FTS_DP:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ case FTS_DEFAULT:
+ VLOG(1) << "Removing " << curr->fts_path;
+ if (remove(curr->fts_accpath) < 0) {
+ LOG(WARNING) << curr->fts_path
+ << ": Failed to remove: " << strerror(curr->fts_errno);
+ }
+ break;
+ }
+ }
+
+ if (ftsp) {
+ fts_close(ftsp);
+ }
+}
+
} // namespace util
} // namespace aos
diff --git a/aos/util/file.h b/aos/util/file.h
index bf216bb..4d0ed2d 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -26,6 +26,10 @@
bool PathExists(std::string_view path);
+// Recursively removes everything in the provided path. Ignores any errors it
+// runs across.
+void UnlinkRecursive(std::string_view path);
+
} // namespace util
} // namespace aos
diff --git a/debian/fts.patch b/debian/fts.patch
new file mode 100644
index 0000000..7357940
--- /dev/null
+++ b/debian/fts.patch
@@ -0,0 +1,11 @@
+--- arm-frc2020-linux-gnueabi/usr/include/fts.h
++++ arm-frc2020-linux-gnueabi/usr/include/fts.h
+@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int,
+ int (*)(const FTSENT **, const FTSENT **)),
+ fts64_open);
+ FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read);
+-int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW;
++int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set);
+ # else
+ # define fts_children fts64_children
+ # define fts_close fts64_close