tests: Add test for IPCPipeUnixSocket
Test the IPC functions of IPCPipeUnixSocket. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
01fd806b9a
commit
f70d5b14d6
2 changed files with 233 additions and 1 deletions
|
@ -1,6 +1,7 @@
|
|||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
ipc_tests = [
|
||||
['unixsocket_ipc', 'unixsocket_ipc.cpp'],
|
||||
['unixsocket', 'unixsocket.cpp'],
|
||||
]
|
||||
|
||||
|
|
231
test/ipc/unixsocket_ipc.cpp
Normal file
231
test/ipc/unixsocket_ipc.cpp
Normal file
|
@ -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();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue