summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/ipc/meson.build3
-rw-r--r--test/ipc/unixsocket_ipc.cpp231
2 files changed, 233 insertions, 1 deletions
diff --git a/test/ipc/meson.build b/test/ipc/meson.build
index 9f413ff6..ad47b2fe 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..3049eaa8
--- /dev/null
+++ b/test/ipc/unixsocket_ipc.cpp
@@ -0,0 +1,231 @@
+/* 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 <limits.h>
+#include <stdlib.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"
+
+
+using namespace std;
+using namespace libcamera;
+
+enum {
+ CmdExit = 0,
+ CmdGetSync = 1,
+ CmdSetAsync = 2,
+};
+
+const int32_t kInitialValue = 1337;
+const int32_t kChangedValue = 9001;
+
+class UnixSocketTestIPCSlave
+{
+public:
+ UnixSocketTestIPCSlave()
+ : value_(kInitialValue), 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 CmdExit: {
+ exit_ = true;
+ break;
+ }
+
+ case CmdGetSync: {
+ 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 CmdSetAsync: {
+ 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 setValue(int32_t val)
+ {
+ IPCMessage msg(CmdSetAsync);
+ tie(msg.data(), ignore) = IPADataSerializer<int32_t>::serialize(val);
+
+ int ret = ipc_->sendAsync(msg);
+ if (ret < 0) {
+ cerr << "Failed to call set value" << endl;
+ return ret;
+ }
+
+ return 0;
+ }
+
+ int getValue()
+ {
+ IPCMessage msg(CmdGetSync);
+ IPCMessage buf;
+
+ int ret = ipc_->sendSync(msg, &buf);
+ if (ret < 0) {
+ cerr << "Failed to call get value" << endl;
+ return ret;
+ }
+
+ return IPADataSerializer<int32_t>::deserialize(buf.data());
+ }
+
+ int exit()
+ {
+ IPCMessage msg(CmdExit);
+
+ int ret = ipc_->sendAsync(msg);
+ if (ret < 0) {
+ cerr << "Failed to call exit" << endl;
+ return ret;
+ }
+
+ return 0;
+ }
+
+ int run()
+ {
+ ipc_ = std::make_unique<IPCPipeUnixSocket>("", "/proc/self/exe");
+ if (!ipc_->isConnected()) {
+ cerr << "Failed to create IPCPipe" << endl;
+ return TestFail;
+ }
+
+ int ret = getValue();
+ if (ret != kInitialValue) {
+ cerr << "Wrong initial value, expected "
+ << kInitialValue << ", got " << ret << endl;
+ return TestFail;
+ }
+
+ ret = setValue(kChangedValue);
+ if (ret < 0) {
+ cerr << "Failed to set value: " << strerror(-ret) << endl;
+ return TestFail;
+ }
+
+ ret = getValue();
+ if (ret != kChangedValue) {
+ cerr << "Wrong set value, expected " << kChangedValue
+ << ", 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 client and
+ * server
+ */
+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();
+}