diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/ipc/meson.build | 3 | ||||
-rw-r--r-- | test/ipc/unixsocket_ipc.cpp | 231 |
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(); +} |