From patchwork Tue Sep 22 13:35:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 9742 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 B2769BF01C for ; Tue, 22 Sep 2020 13:40:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7600863007; Tue, 22 Sep 2020 15:40:28 +0200 (CEST) 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="Mc4dX3pq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ED71E62FD6 for ; Tue, 22 Sep 2020 15:40:26 +0200 (CEST) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 79A272D7; Tue, 22 Sep 2020 15:40:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1600782022; bh=R98fkUPI6oF+rfCFvdCP0/3i7iEum0eIqaclFF9QjWM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Mc4dX3pqX+yTLxrCcRycCUYMlWL8Ti50l7AXHBMkN4VQvwDXSD9nQl96cfefwV8Lx F4FAxKhaYUE+i7d9wK1Zb0bcWYRC8nMIKnhXSJj5ypdPiKfT/ecFnhBMDhWF/kxm7c a633IYHOL2yMdRSMB4OCgMOuztbDKKelhwa9Y3Fc= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 22 Sep 2020 22:35:37 +0900 Message-Id: <20200922133537.258098-39-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200922133537.258098-1-paul.elder@ideasonboard.com> References: <20200922133537.258098-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 38/38] tests: Add test for IPAIPCUnixSocket 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 IPAIPCUnixSocket. Signed-off-by: Paul Elder --- New in v2 --- test/ipc/meson.build | 3 +- test/ipc/unixsocket_ipc.cpp | 238 ++++++++++++++++++++++++++++++++++++ 2 files changed, 240 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..1f2d2815 --- /dev/null +++ b/test/ipc/unixsocket_ipc.cpp @@ -0,0 +1,238 @@ +/* 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 +#include + +#include "libcamera/internal/ipa_data_serializer.h" +#include "libcamera/internal/ipa_ipc_unixsocket.h" +#include "libcamera/internal/process.h" +#include "libcamera/internal/thread.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, response; + int ret; + + ret = ipc->receive(&message); + if (ret) { + cerr << "Receive message failed: " << ret << endl; + return; + } + + uint32_t cmd, seq; + std::tie(cmd, seq) = readHeader(message); + eraseHeader(message); + + switch (cmd) { + case CMD_EXIT: { + exit_ = true; + break; + } + + case CMD_GET_SYNC: { + writeHeader(response, cmd, seq); + + vector buf; + tie(buf, ignore) = IPADataSerializer::serialize(value_); + response.data.insert(response.data.end(), buf.begin(), buf.end()); + + ret = ipc_.send(response); + if (ret < 0) { + cerr << "Reply failed" << endl; + stop(ret); + } + break; + } + + case CMD_SET_ASYNC: { + value_ = IPADataSerializer::deserialize(message.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) + { + vector buf; + tie(buf, 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() + { + vector 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); + } + + 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_->isValid()) { + cerr << "Failed to create IPAIPC" << 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_; + + std::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) +{ + /* IPAIPCUnixSocket 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(); +}