blob: 84cc24888c778bad810a2d4a6d715e123bb1833a [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 "missive/scheduler/enqueue_job.h"
#include <memory>
#include <string>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include <base/bind.h>
#include <base/run_loop.h>
#include <base/test/task_environment.h>
#include <brillo/dbus/dbus_method_response.h>
#include <brillo/dbus/mock_dbus_method_response.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "missive/storage/storage_module_interface.h"
#include "missive/util/status.h"
namespace reporting {
namespace {
using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::NotNull;
using ::testing::WithArgs;
class TestCallbackWaiter {
public:
TestCallbackWaiter() : run_loop_(std::make_unique<base::RunLoop>()) {}
virtual void Signal() { run_loop_->Quit(); }
void Complete() { Signal(); }
void Wait() { run_loop_->Run(); }
protected:
std::unique_ptr<base::RunLoop> run_loop_;
};
MATCHER_P(EqualsProto,
message,
"Match a proto Message equal to the matcher's argument.") {
std::string expected_serialized, actual_serialized;
message.SerializeToString(&expected_serialized);
arg.SerializeToString(&actual_serialized);
return expected_serialized == actual_serialized;
}
class MockStorageModule : public StorageModuleInterface {
public:
static scoped_refptr<MockStorageModule> Create() {
return base::WrapRefCounted(new MockStorageModule());
}
MOCK_METHOD(void,
AddRecord,
(Priority, Record, base::OnceCallback<void(Status)>),
(override));
MOCK_METHOD(void, ReportSuccess, (SequencingInformation, bool), (override));
MOCK_METHOD(void, UpdateEncryptionKey, (SignedEncryptionInfo), (override));
};
class EnqueueJobTest : public ::testing::Test {
public:
EnqueueJobTest() : method_call_("org.Test", "TestMethod") {}
protected:
void SetUp() override {
response_ = std::make_unique<
brillo::dbus_utils::MockDBusMethodResponse<EnqueueRecordResponse>>(
&method_call_);
ASSERT_FALSE(response_->IsResponseSent());
record_.set_data("TEST_VALUE");
record_.set_destination(Destination::UPLOAD_EVENTS);
record_.set_dm_token("TEST_DM_TOKEN");
record_.set_timestamp_us(1234567);
fd_ = memfd_create("TempMemFile", 0);
ASSERT_GE(fd_, 0);
ASSERT_TRUE(record_.SerializeToFileDescriptor(fd_));
pid_ = getpid();
storage_module_ = MockStorageModule::Create();
}
void TearDown() override {
if (fd_ >= 0) {
close(fd_);
}
}
base::test::TaskEnvironment task_environment_;
dbus::MethodCall method_call_;
std::unique_ptr<
brillo::dbus_utils::MockDBusMethodResponse<EnqueueRecordResponse>>
response_;
Record record_;
int fd_;
pid_t pid_;
scoped_refptr<MockStorageModule> storage_module_;
};
TEST_F(EnqueueJobTest, CompletesSuccessfully) {
response_->set_return_callback(
base::Bind([](const EnqueueRecordResponse& response) {
LOG(ERROR) << response.status().error_message();
EXPECT_EQ(response.status().code(), error::OK);
}));
auto delegate = std::make_unique<EnqueueJob::EnqueueResponseDelegate>(
std::move(response_));
EnqueueRecordRequest request;
request.set_record_fd(fd_);
request.set_pid(pid_);
request.set_priority(Priority::BACKGROUND_BATCH);
EXPECT_CALL(*storage_module_, AddRecord(Eq(Priority::BACKGROUND_BATCH),
EqualsProto(record_), _))
.WillOnce(WithArgs<2>(Invoke([](base::OnceCallback<void(Status)> cb) {
std::move(cb).Run(Status::StatusOK());
})));
EnqueueJob job(storage_module_, request, std::move(delegate));
TestCallbackWaiter waiter;
job.Start(base::BindOnce(
[](TestCallbackWaiter* waiter, Status status) {
EXPECT_TRUE(status.ok());
waiter->Signal();
},
&waiter));
waiter.Wait();
}
TEST_F(EnqueueJobTest, CancelsSuccessfully) {
Status failure_status(error::INTERNAL, "Failing for tests");
response_->set_return_callback(base::Bind(
[](Status status, const EnqueueRecordResponse& response) {
EXPECT_TRUE(response.status().code() == status.error_code());
},
failure_status));
auto delegate = std::make_unique<EnqueueJob::EnqueueResponseDelegate>(
std::move(response_));
EnqueueRecordRequest request;
request.set_record_fd(fd_);
request.set_pid(pid_);
request.set_priority(Priority::BACKGROUND_BATCH);
EnqueueJob job(storage_module_, request, std::move(delegate));
auto status = job.Cancel(failure_status);
EXPECT_TRUE(status.ok());
}
} // namespace
} // namespace reporting