[libcamera-devel] [PATCH v6 2/4] tests: Add test for IPCPipeUnixSocket
Paul Elder
paul.elder at ideasonboard.com
Thu Dec 24 09:17:11 CET 2020
Test the IPC functions of IPCPipeUnixSocket.
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
No change in v6
Changes in v5:
- rename IPAIPCUnixSocket to IPCPipeUnixSocket
- use IPCMessage
No change in v4
Changes in v3:
- use readHeader, writeHeader, and eraseHeader as static class functions
of IPAIPCUnixSocket
New in v2
---
test/ipc/meson.build | 3 +-
test/ipc/unixsocket_ipc.cpp | 237 ++++++++++++++++++++++++++++++++++++
2 files changed, 239 insertions(+), 1 deletion(-)
create mode 100644 test/ipc/unixsocket_ipc.cpp
diff --git a/test/ipc/meson.build b/test/ipc/meson.build
index 650df1d6..ecb6d022 100644
--- a/test/ipc/meson.build
+++ b/test/ipc/meson.build
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: CC0-1.0
ipc_tests = [
- [ 'unixsocket', 'unixsocket.cpp' ],
+ [ 'unixsocket_ipc', 'unixsocket_ipc.cpp' ],
+ [ 'unixsocket', 'unixsocket.cpp' ],
]
foreach t : ipc_tests
diff --git a/test/ipc/unixsocket_ipc.cpp b/test/ipc/unixsocket_ipc.cpp
new file mode 100644
index 00000000..827689f7
--- /dev/null
+++ b/test/ipc/unixsocket_ipc.cpp
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * unixsocket_ipc.cpp - Unix socket IPC test
+ */
+
+#include <algorithm>
+#include <fcntl.h>
+#include <iostream>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "libcamera/internal/event_dispatcher.h"
+#include "libcamera/internal/ipa_data_serializer.h"
+#include "libcamera/internal/ipc_pipe.h"
+#include "libcamera/internal/ipc_pipe_unixsocket.h"
+#include "libcamera/internal/process.h"
+#include "libcamera/internal/thread.h"
+#include "libcamera/internal/timer.h"
+#include "libcamera/internal/utils.h"
+
+#include "test.h"
+
+#define CMD_EXIT 0
+#define CMD_GET_SYNC 1
+#define CMD_SET_ASYNC 2
+
+using namespace std;
+using namespace libcamera;
+
+class UnixSocketTestIPCSlave
+{
+public:
+ UnixSocketTestIPCSlave()
+ : value_(1337), exitCode_(EXIT_FAILURE), exit_(false)
+ {
+ dispatcher_ = Thread::current()->eventDispatcher();
+ ipc_.readyRead.connect(this, &UnixSocketTestIPCSlave::readyRead);
+ }
+
+ int run(int fd)
+ {
+ if (ipc_.bind(fd)) {
+ cerr << "Failed to connect to IPC channel" << endl;
+ return EXIT_FAILURE;
+ }
+
+ while (!exit_)
+ dispatcher_->processEvents();
+
+ ipc_.close();
+
+ return exitCode_;
+ }
+
+private:
+ void readyRead(IPCUnixSocket *ipc)
+ {
+ IPCUnixSocket::Payload message;
+ int ret;
+
+ ret = ipc->receive(&message);
+ if (ret) {
+ cerr << "Receive message failed: " << ret << endl;
+ return;
+ }
+
+ IPCMessage ipcMessage(message);
+ uint32_t cmd = ipcMessage.header().cmd;
+
+ switch (cmd) {
+ case CMD_EXIT: {
+ exit_ = true;
+ break;
+ }
+
+ case CMD_GET_SYNC: {
+ IPCMessage::Header header = { cmd, ipcMessage.header().cookie };
+ IPCMessage response(header);
+
+ vector<uint8_t> buf;
+ tie(buf, ignore) = IPADataSerializer<int32_t>::serialize(value_);
+ response.data().insert(response.data().end(), buf.begin(), buf.end());
+
+ ret = ipc_.send(response.payload());
+ if (ret < 0) {
+ cerr << "Reply failed" << endl;
+ stop(ret);
+ }
+ break;
+ }
+
+ case CMD_SET_ASYNC: {
+ value_ = IPADataSerializer<int32_t>::deserialize(ipcMessage.data());
+ break;
+ }
+ }
+ }
+
+ void stop(int code)
+ {
+ exitCode_ = code;
+ exit_ = true;
+ }
+
+ int32_t value_;
+
+ IPCUnixSocket ipc_;
+ EventDispatcher *dispatcher_;
+ int exitCode_;
+ bool exit_;
+};
+
+class UnixSocketTestIPC : public Test
+{
+protected:
+ int init()
+ {
+ return 0;
+ }
+
+ int setVal(int32_t val)
+ {
+ IPCMessage buf;
+ tie(buf.data(), ignore) = IPADataSerializer<int32_t>::serialize(val);
+
+ int ret = ipc_->sendAsync(CMD_SET_ASYNC, buf);
+ if (ret < 0) {
+ cerr << "Failed to call set value" << endl;
+ return ret;
+ }
+
+ return 0;
+ }
+
+ int getVal()
+ {
+ IPCMessage buf;
+
+ int ret = ipc_->sendSync(CMD_GET_SYNC, {}, &buf);
+ if (ret < 0) {
+ cerr << "Failed to call get value" << endl;
+ return ret;
+ }
+
+ return IPADataSerializer<int32_t>::deserialize(buf.data());
+ }
+
+ int exit()
+ {
+ int ret = ipc_->sendAsync(CMD_EXIT, {});
+ if (ret < 0) {
+ cerr << "Failed to call exit" << endl;
+ return ret;
+ }
+
+ return 0;
+ }
+
+ int run()
+ {
+ char selfpath[100];
+ memset(selfpath, 0, sizeof(selfpath));
+ int ret = readlink("/proc/self/exe", selfpath, sizeof(selfpath));
+ if (ret < 0) {
+ int err = errno;
+ cerr << "Failed to get path: " << strerror(err) << endl;
+ return TestFail;
+ }
+
+ ipc_ = std::make_unique<IPCPipeUnixSocket>("", selfpath);
+ if (!ipc_->isConnected()) {
+ cerr << "Failed to create IPCPipe" << endl;
+ return TestFail;
+ }
+
+ ret = getVal();
+ if (ret < 0) {
+ cerr << "Failed to get initial value: " << strerror(-ret) << endl;
+ return TestFail;
+ }
+ if (ret != 1337) {
+ cerr << "Wrong inital value, expected 1337, got " << ret << endl;
+ return TestFail;
+ }
+
+ ret = setVal(9001);
+ if (ret < 0) {
+ cerr << "Failed to set value: " << strerror(-ret) << endl;
+ return TestFail;
+ }
+
+ ret = getVal();
+ if (ret < 0) {
+ cerr << "Failed to get value: " << strerror(-ret) << endl;
+ return TestFail;
+ }
+ if (ret != 9001) {
+ cerr << "Wrong set value, expected 9001, got " << ret << endl;
+ return TestFail;
+ }
+
+ ret = exit();
+ if (ret < 0) {
+ cerr << "Failed to exit: " << strerror(-ret) << endl;
+ return TestFail;
+ }
+
+ return TestPass;
+ }
+
+private:
+ ProcessManager processManager_;
+
+ unique_ptr<IPCPipeUnixSocket> ipc_;
+};
+
+/*
+ * Can't use TEST_REGISTER() as single binary needs to act as both proxy
+ * master and slave.
+ */
+int main(int argc, char **argv)
+{
+ /* IPCPipeUnixSocket passes IPA module path in argv[1] */
+ if (argc == 3) {
+ int ipcfd = std::stoi(argv[2]);
+ UnixSocketTestIPCSlave slave;
+ return slave.run(ipcfd);
+ }
+
+ return UnixSocketTestIPC().execute();
+}
--
2.27.0
More information about the libcamera-devel
mailing list