Skip to content

Commit

Permalink
nixd/librpc: add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Mar 13, 2024
1 parent 1e086b7 commit b5a9b05
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 22 deletions.
36 changes: 30 additions & 6 deletions nixd/librpc/include/nixd/rpc/Protocol.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "Protocol.h"
#include <bc/Read.h>
#include <bc/Write.h>

#include <cstdint>
#include <cstring>
Expand Down Expand Up @@ -30,6 +31,26 @@ enum class RPCKind : uint8_t {
ExprValue,
};

template <class T> struct Message {
RPCKind Kind;
T Params;

Message() = default;
Message(RPCKind Kind, T Params) : Kind(Kind), Params(Params) {}
};

template <class T> void writeBytecode(std::ostream &OS, const Message<T> &Msg) {
using bc::writeBytecode;
writeBytecode(OS, Msg.Kind);
writeBytecode(OS, Msg.Params);
}

template <class T> void readBytecode(std::string_view &Data, Message<T> &Msg) {
using bc::readBytecode;
readBytecode(Data, Msg.Kind);
readBytecode(Data, Msg.Params);
}

struct RegisterBCParams {
std::string Shm;
std::size_t Size;
Expand All @@ -45,10 +66,10 @@ struct ExprValueParams {
};

void writeBytecode(std::ostream &OS, const ExprValueParams &Params);
void readBytecode(std::string_view &Data, const ExprValueParams &Params);
void readBytecode(std::string_view &Data, ExprValueParams &Params);

struct ExprValueResponse {
enum class Kind {
enum ResultKinds {
/// \brief The expr is not found in the registered bytecodes.
NotFound,

Expand All @@ -60,18 +81,21 @@ struct ExprValueResponse {

/// \brief The value is available.
OK,
};
} ResultKind;
/// \brief The value ID, for future reference.
///
/// We may want to query the value of the same expr multiple times, with more
/// detailed information.
std::uintptr_t ValueID;

/// \brief Opaque data, the value of the expr.
enum class ValueKind {
enum ValueKinds {
Int,
Float,
};
} ValueKind;
};

void writeBytecode(std::ostream &OS, const ExprValueResponse &Params);
void readBytecode(std::string_view &Data, ExprValueResponse &Params);

} // namespace nixd::rpc
33 changes: 23 additions & 10 deletions nixd/librpc/include/nixd/rpc/Transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,37 @@

namespace nixd::rpc {

/// \brief Wraps a message with it's length, and then send it.
void send(int OutboundFD, std::string_view Msg);

/// \brief Wraps a message with it's length, and then send it.
std::vector<char> recv(int InboundFD);

template <class T> T recvPacket(int InboundFD) {
std::vector<char> Buf = recv(InboundFD);
T Data;
std::string_view D = {Buf.begin(), Buf.end()};
readBytecode(D, Data);
return Data;
}

template <class T> void sendPacket(int OutboundFD, const T &Data) {
auto Str = bc::toBytecode(Data);
send(OutboundFD, Str);
}

class Transport {
int InboundFD;
int OutboundFD;

protected:
/// \brief Wraps a message with it's length, and then send it.
void send(std::string_view Msg) const;
void send(std::string_view Msg) const { rpc::send(OutboundFD, Msg); }

/// \brief Read a message and then forms a packet.
[[nodiscard]] std::vector<char> recv() const;
/// \brief Wraps a message with it's length, and then send it.
[[nodiscard]] std::vector<char> recv() const { return rpc::recv(InboundFD); }

template <class T> T recvPacket() const {
std::vector<char> Buf = recv();
T Data;
std::string_view D = {Buf.begin(), Buf.end()};
readBytecode(D, Data);
return Data;
}
template <class T> T recvPacket() { return rpc::recvPacket<T>(InboundFD); }

template <class T> void sendPacket(const T &Data) {
auto Str = bc::toBytecode(Data);
Expand Down
7 changes: 7 additions & 0 deletions nixd/librpc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ libnixdrpc = declare_dependency(
dependencies: libnixdrpc_deps,
)

test('unit/nixd/librpc',
executable(
'unit-nixd-librpc',
'test/Transport.cpp',
dependencies: [ gtest_main, libnixdrpc ]
)
)
4 changes: 3 additions & 1 deletion nixd/librpc/src/IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ size_t readBytes(int FD, void *Buf, std::size_t N) {
size_t Read = 0;
while (Read < N) {
size_t BytesRead = read(FD, static_cast<char *>(Buf) + Read, N - Read);
if (BytesRead <= 0)
if (BytesRead < 0)
throw std::system_error(std::make_error_code(std::errc(errno)));
if (BytesRead == 0)
break;
Read += BytesRead;
}
return Read;
Expand Down
24 changes: 21 additions & 3 deletions nixd/librpc/src/Protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#include <bc/Read.h>
#include <bc/Write.h>

#include <cstring>
#include <sstream>

namespace nixd::rpc {

using bc::readBytecode;
Expand All @@ -23,4 +20,25 @@ void readBytecode(std::string_view &Data, RegisterBCParams &Params) {
readBytecode(Data, Params.BCID);
}

void writeBytecode(std::ostream &OS, const ExprValueParams &Params) {
writeBytecode(OS, Params.ExprID);
writeBytecode(OS, Params.BCID);
}

void readBytecode(std::string_view &Data, ExprValueParams &Params) {
readBytecode(Data, Params.ExprID);
readBytecode(Data, Params.BCID);
}

void writeBytecode(std::ostream &OS, const ExprValueResponse &Params) {
writeBytecode(OS, Params.ValueKind);
writeBytecode(OS, Params.ValueID);
writeBytecode(OS, Params.ResultKind);
}
void readBytecode(std::string_view &Data, ExprValueResponse &Params) {
readBytecode(Data, Params.ValueKind);
readBytecode(Data, Params.ValueID);
readBytecode(Data, Params.ResultKind);
}

} // namespace nixd::rpc
4 changes: 2 additions & 2 deletions nixd/librpc/src/Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ namespace nixd::rpc {

using MessageSizeT = std::size_t;

void Transport::send(std::string_view Msg) const {
void send(int OutboundFD, std::string_view Msg) {
MessageSizeT Size = Msg.size();
if (write(OutboundFD, &Size, sizeof(MessageSizeT)) < 0)
throw std::system_error(std::make_error_code(std::errc(errno)));
if (write(OutboundFD, Msg.data(), Msg.size()) < 0)
throw std::system_error(std::make_error_code(std::errc(errno)));
}

std::vector<char> Transport::recv() const {
std::vector<char> recv(int InboundFD) {
MessageSizeT Size;
readBytes(InboundFD, &Size, sizeof(Size));

Expand Down
41 changes: 41 additions & 0 deletions nixd/librpc/test/Transport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <gtest/gtest.h>

#include "nixd/rpc/Protocol.h"
#include "nixd/rpc/Transport.h"

namespace {

using namespace nixd::rpc;

#define PIPE_READ 0
#define PIPE_WRITE 1

TEST(RPC, Message) {
std::string Msg = "foo";

int Pipes[2];
ASSERT_EQ(pipe(Pipes), 0);

send(Pipes[PIPE_WRITE], Msg);

auto Result = recv(Pipes[PIPE_READ]);

ASSERT_EQ(Result.size(), Msg.size());
}

TEST(RPC, MessageEval) {
int Pipes[2];
ASSERT_EQ(pipe(Pipes), 0);

using DataT = Message<ExprValueParams>;

sendPacket(Pipes[PIPE_WRITE],
DataT{RPCKind::ExprValue, ExprValueParams{1, 2}});

auto Msg = recvPacket<DataT>(Pipes[PIPE_READ]);

ASSERT_EQ(Msg.Params.BCID, 1);
ASSERT_EQ(Msg.Params.ExprID, 2);
}

} // namespace

0 comments on commit b5a9b05

Please sign in to comment.