blob: cfb4415047550b675967915e6e9e4f4ea54b8555 [file] [log] [blame] [edit]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/lib/paver/stream-reader.h"
#include <fcntl.h>
#include <fuchsia/paver/llcpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl-async/cpp/bind.h>
#include <zxtest/zxtest.h>
namespace {
constexpr char kFileData[] = "lalalala";
TEST(StreamReaderTest, InvalidChannel) {
ASSERT_NOT_OK(paver::StreamReader::Create(zx::channel()));
}
class FakePayloadStream : public ::llcpp::fuchsia::paver::PayloadStream::Interface {
public:
FakePayloadStream() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {
zx::channel server;
ASSERT_OK(zx::channel::create(0, &client_, &server));
fidl::BindSingleInFlightOnly(loop_.dispatcher(), std::move(server), this);
loop_.StartThread("payload-stream-test-loop");
}
void ReadSuccess(ReadDataCompleter::Sync& completer) {
vmo_.write(kFileData, 0, sizeof(kFileData));
::llcpp::fuchsia::paver::ReadInfo info{.offset = 0, .size = sizeof(kFileData)};
completer.Reply(::llcpp::fuchsia::paver::ReadResult::WithInfo(fidl::unowned_ptr(&info)));
}
void ReadError(ReadDataCompleter::Sync& completer) {
::llcpp::fuchsia::paver::ReadResult result;
zx_status_t status = ZX_ERR_INTERNAL;
result.set_err(fidl::unowned_ptr(&status));
completer.Reply(std::move(result));
}
void ReadEof(ReadDataCompleter::Sync& completer) {
::llcpp::fuchsia::paver::ReadResult result;
fidl::aligned<bool> eof = true;
result.set_eof(fidl::unowned_ptr(&eof));
completer.Reply(std::move(result));
}
void ReadData(ReadDataCompleter::Sync& completer) {
if (!vmo_) {
::llcpp::fuchsia::paver::ReadResult result;
zx_status_t status = ZX_ERR_BAD_STATE;
result.set_err(fidl::unowned_ptr(&status));
completer.Reply(std::move(result));
return;
}
if (return_err_) {
ReadError(completer);
} else if (return_eof_) {
ReadEof(completer);
} else {
ReadSuccess(completer);
}
}
void RegisterVmo(zx::vmo vmo, RegisterVmoCompleter::Sync& completer) {
vmo_ = std::move(vmo);
completer.Reply(ZX_OK);
}
zx::channel client() { return std::move(client_); }
void ReturnErr() { return_err_ = true; }
void ReturnEof() { return_eof_ = true; }
private:
zx::channel client_;
async::Loop loop_;
zx::vmo vmo_;
bool return_err_ = false;
bool return_eof_ = false;
};
class StreamReaderTest : public zxtest::Test {
protected:
FakePayloadStream stream_;
};
TEST_F(StreamReaderTest, Create) { ASSERT_OK(paver::StreamReader::Create(stream_.client())); }
TEST_F(StreamReaderTest, ReadError) {
auto status = paver::StreamReader::Create(stream_.client());
ASSERT_OK(status);
std::unique_ptr<paver::StreamReader> reader = std::move(status.value());
stream_.ReturnErr();
char buffer[sizeof(kFileData)] = {};
size_t actual;
ASSERT_NE(reader->Read(buffer, sizeof(buffer), &actual), ZX_OK);
}
TEST_F(StreamReaderTest, ReadEof) {
auto status = paver::StreamReader::Create(stream_.client());
ASSERT_OK(status);
std::unique_ptr<paver::StreamReader> reader = std::move(status.value());
stream_.ReturnEof();
char buffer[sizeof(kFileData)] = {};
size_t actual;
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, 0);
}
TEST_F(StreamReaderTest, ReadSingle) {
auto status = paver::StreamReader::Create(stream_.client());
ASSERT_OK(status);
std::unique_ptr<paver::StreamReader> reader = std::move(status.value());
char buffer[sizeof(kFileData)] = {};
size_t actual;
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, sizeof(buffer));
ASSERT_EQ(memcmp(buffer, kFileData, sizeof(buffer)), 0);
stream_.ReturnEof();
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, 0);
}
TEST_F(StreamReaderTest, ReadMultiple) {
auto status = paver::StreamReader::Create(stream_.client());
ASSERT_OK(status);
std::unique_ptr<paver::StreamReader> reader = std::move(status.value());
char buffer[sizeof(kFileData)] = {};
size_t actual;
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, sizeof(buffer));
ASSERT_EQ(memcmp(buffer, kFileData, sizeof(buffer)), 0);
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, sizeof(buffer));
ASSERT_EQ(memcmp(buffer, kFileData, sizeof(buffer)), 0);
stream_.ReturnEof();
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, 0);
}
TEST_F(StreamReaderTest, ReadPartial) {
auto status = paver::StreamReader::Create(stream_.client());
ASSERT_OK(status);
std::unique_ptr<paver::StreamReader> reader = std::move(status.value());
constexpr size_t kBufferSize = sizeof(kFileData) - 3;
char buffer[kBufferSize] = {};
size_t actual;
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, sizeof(buffer));
ASSERT_EQ(memcmp(buffer, kFileData, sizeof(buffer)), 0);
stream_.ReturnEof();
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, 3);
ASSERT_EQ(memcmp(buffer, kFileData + kBufferSize, 3), 0);
ASSERT_OK(reader->Read(buffer, sizeof(buffer), &actual));
ASSERT_EQ(actual, 0);
}
} // namespace