From patchwork Sat Dec 5 10:31:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 10584 X-Patchwork-Delegate: paul.elder@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id AF902BDB20 for ; Sat, 5 Dec 2020 10:32:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7DCBC635FA; Sat, 5 Dec 2020 11:32:03 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ob9MiEqb"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9DD44635F7 for ; Sat, 5 Dec 2020 11:32:02 +0100 (CET) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4C9642A4; Sat, 5 Dec 2020 11:32:01 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1607164322; bh=X4krYc102aiM/pHeH3b5FqwvVyas206y5KBVn3DGO7Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ob9MiEqb/1/h7pHMu5eDclugJujNR2N2z+iTl7DktkzSsvhbjFp7/v4ZgmkiB74WB +AAnbdQuOS+RONtPCYDq0jbjevu8HfLq9uOoxhCFaXj6afCzU575RbZRy3kRvxpszZ l1QfODSV/P2mQssvYvUhrPY8Zu+jHiuOD1jZtrkE= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Sat, 5 Dec 2020 19:31:04 +0900 Message-Id: <20201205103106.242080-22-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201205103106.242080-1-paul.elder@ideasonboard.com> References: <20201205103106.242080-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 21/23] tests: Add test for IPCPipeUnixSocket X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Test the IPC functions of IPCPipeUnixSocket. Signed-off-by: Paul Elder --- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 buf; + tie(buf, ignore) = IPADataSerializer::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::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::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::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("", 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 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(); +}