Files
nearby/sharing/linux/daemon/daemon_service_test.cc
T

307 lines
11 KiB
C++

#include "sharing/linux/daemon/daemon_service.h"
#include <gtest/gtest.h>
#include <functional>
#include <fstream>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <cstdio>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/time/time.h"
#include "nlohmann/json.hpp"
#include "sharing/attachment_container.h"
#include "sharing/nearby_sharing_service.h"
#include "sharing/share_target.h"
#include "sharing/share_target_discovered_callback.h"
#include "sharing/transfer_metadata.h"
#include "sharing/transfer_metadata_builder.h"
#include "sharing/transfer_update_callback.h"
namespace nearby::sharing::linux {
namespace {
ShareTarget MakeTarget(int64_t id, std::string name = "Pixel") {
ShareTarget target;
target.id = id;
target.device_name = std::move(name);
return target;
}
std::unique_ptr<AttachmentContainer> MakeAttachments() {
AttachmentContainer::Builder builder;
return builder.Build();
}
TransferMetadata MakeMetadata(TransferMetadata::Status status) {
return TransferMetadataBuilder()
.set_status(status)
.set_progress(status == TransferMetadata::Status::kComplete ? 100 : 25)
.set_total_attachments_count(1)
.build();
}
class FakeDaemonNearbySharingService final : public NearbySharingService {
public:
void AddObserver(Observer* observer) override { static_cast<void>(observer); }
void RemoveObserver(Observer* observer) override {
static_cast<void>(observer);
}
void Shutdown(std::function<void(StatusCodes)> callback) override {
shutdown_called = true;
callback(StatusCodes::kOk);
}
void RegisterSendSurface(
TransferUpdateCallback* transfer_callback,
ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state,
Advertisement::BlockedVendorId blocked_vendor_id,
bool disable_wifi_hotspot,
absl::AnyInvocable<void(StatusCodes)> callback) override {
static_cast<void>(blocked_vendor_id);
static_cast<void>(disable_wifi_hotspot);
send_transfer_callback = transfer_callback;
this->discovery_callback = discovery_callback;
send_state = state;
callback(StatusCodes::kOk);
}
void UnregisterSendSurface(
TransferUpdateCallback* transfer_callback,
absl::AnyInvocable<void(StatusCodes)> callback) override {
if (send_transfer_callback == transfer_callback) {
send_transfer_callback = nullptr;
discovery_callback = nullptr;
}
callback(StatusCodes::kOk);
}
void RegisterReceiveSurface(
TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state,
Advertisement::BlockedVendorId vendor_id,
absl::AnyInvocable<void(StatusCodes)> callback) override {
static_cast<void>(vendor_id);
receive_transfer_callback = transfer_callback;
receive_state = state;
callback(StatusCodes::kOk);
}
void UnregisterReceiveSurface(
TransferUpdateCallback* transfer_callback,
absl::AnyInvocable<void(StatusCodes)> callback) override {
if (receive_transfer_callback == transfer_callback) {
receive_transfer_callback = nullptr;
}
callback(StatusCodes::kOk);
}
void ClearForegroundReceiveSurfaces(
absl::AnyInvocable<void(StatusCodes)> callback) override {
callback(StatusCodes::kOk);
}
bool IsTransferring() const override { return false; }
bool IsScanning() const override { return discovery_callback != nullptr; }
bool IsBluetoothPresent() const override { return true; }
bool IsBluetoothPowered() const override { return true; }
bool IsExtendedAdvertisingSupported() const override { return true; }
bool IsLanConnected() const override { return true; }
std::string GetQrCodeUrl() const override { return ""; }
void SendAttachments(
int64_t share_target_id,
std::unique_ptr<AttachmentContainer> attachment_container,
std::function<void(StatusCodes)> callback) override {
last_send_target_id = share_target_id;
last_attachment_count = attachment_container == nullptr
? 0
: attachment_container->GetAttachmentCount();
callback(StatusCodes::kOk);
}
void Accept(int64_t share_target_id,
std::function<void(StatusCodes)> callback) override {
last_accept_target_id = share_target_id;
callback(StatusCodes::kOk);
}
void Reject(int64_t share_target_id,
std::function<void(StatusCodes)> callback) override {
last_reject_target_id = share_target_id;
callback(StatusCodes::kOk);
}
void Cancel(int64_t share_target_id,
std::function<void(StatusCodes)> callback) override {
last_cancel_target_id = share_target_id;
callback(StatusCodes::kOk);
}
void InitiatePairing(
int64_t share_target_id,
service::proto::BindingRequest::Type binding_type,
absl::AnyInvocable<void(StatusCodes status_codes) &&> callback) override {
static_cast<void>(share_target_id);
static_cast<void>(binding_type);
std::move(callback)(StatusCodes::kOk);
}
void SetVisibility(
proto::DeviceVisibility visibility, absl::Duration expiration,
absl::AnyInvocable<void(StatusCodes status_code) &&> callback) override {
static_cast<void>(visibility);
static_cast<void>(expiration);
std::move(callback)(StatusCodes::kOk);
}
std::string Dump() const override { return ""; }
void UpdateFilePathsInProgress(bool update_file_paths) override {
static_cast<void>(update_file_paths);
}
NearbyShareSettings* GetSettings() override { return nullptr; }
NearbyShareCertificateManager* GetCertificateManager() override {
return nullptr;
}
AccountManager* GetAccountManager() override { return nullptr; }
Clock& GetClock() override { throw std::logic_error("unused"); }
void SetAlternateServiceUuidForDiscovery(uint16_t uuid) override {
static_cast<void>(uuid);
}
SyncManager& sync_manager() override { throw std::logic_error("unused"); }
OutgoingTargetsManager& outgoing_targets_manager() override {
throw std::logic_error("unused");
}
void UpdateBackupSavePath(
absl::string_view binding_id, absl::string_view save_path,
absl::AnyInvocable<void(NearbySharingService::StatusCodes)> callback)
override {
static_cast<void>(binding_id);
static_cast<void>(save_path);
callback(StatusCodes::kOk);
}
void FireShareTargetDiscovered(const ShareTarget& target) {
discovery_callback->OnShareTargetDiscovered(target);
}
void FireShareTargetLost(const ShareTarget& target) {
discovery_callback->OnShareTargetLost(target);
}
void FireReceiveTransferUpdate(const ShareTarget& target,
const AttachmentContainer& attachments,
const TransferMetadata& metadata) {
receive_transfer_callback->OnTransferUpdate(target, attachments, metadata);
}
TransferUpdateCallback* send_transfer_callback = nullptr;
TransferUpdateCallback* receive_transfer_callback = nullptr;
ShareTargetDiscoveredCallback* discovery_callback = nullptr;
SendSurfaceState send_state = SendSurfaceState::kUnknown;
ReceiveSurfaceState receive_state = ReceiveSurfaceState::kUnknown;
bool shutdown_called = false;
int64_t last_send_target_id = 0;
size_t last_attachment_count = 0;
int64_t last_accept_target_id = 0;
int64_t last_reject_target_id = 0;
int64_t last_cancel_target_id = 0;
};
class DaemonServiceTest : public ::testing::Test {
protected:
DaemonServiceTest()
: daemon_(service_, [this](const nlohmann::json& event) {
events_.push_back(event);
}) {}
FakeDaemonNearbySharingService service_;
std::vector<nlohmann::json> events_;
DaemonService daemon_;
};
TEST_F(DaemonServiceTest, StartDiscoveryPublishesDiscoveredTargets) {
nlohmann::json result =
daemon_.HandleCommand({{"command", "start_discovery"}});
ASSERT_TRUE(result["ok"].get<bool>());
service_.FireShareTargetDiscovered(MakeTarget(42));
ASSERT_EQ(events_.size(), 1u);
EXPECT_EQ(events_[0]["event"], "target_discovered");
EXPECT_EQ(events_[0]["share_target"]["id"], 42);
EXPECT_EQ(events_[0]["share_target"]["device_name"], "Pixel");
nlohmann::json status = daemon_.HandleCommand({{"command", "status"}});
ASSERT_TRUE(status["ok"].get<bool>());
ASSERT_EQ(status["targets"].size(), 1u);
EXPECT_EQ(status["targets"][0]["id"], 42);
}
TEST_F(DaemonServiceTest, TargetLostRemovesTargetFromStatus) {
ASSERT_TRUE(
daemon_.HandleCommand({{"command", "start_discovery"}})["ok"].get<bool>());
ShareTarget target = MakeTarget(7);
service_.FireShareTargetDiscovered(target);
service_.FireShareTargetLost(target);
ASSERT_EQ(events_.size(), 2u);
EXPECT_EQ(events_[1]["event"], "target_lost");
nlohmann::json status = daemon_.HandleCommand({{"command", "status"}});
ASSERT_TRUE(status["ok"].get<bool>());
EXPECT_TRUE(status["targets"].empty());
}
TEST_F(DaemonServiceTest, ReceiveAwaitingConfirmationPublishesIncomingTransfer) {
ASSERT_TRUE(
daemon_.HandleCommand({{"command", "start_receive"}})["ok"].get<bool>());
auto attachments = MakeAttachments();
service_.FireReceiveTransferUpdate(
MakeTarget(9), *attachments,
MakeMetadata(TransferMetadata::Status::kAwaitingLocalConfirmation));
ASSERT_EQ(events_.size(), 1u);
EXPECT_EQ(events_[0]["event"], "incoming_transfer");
EXPECT_EQ(events_[0]["direction"], "receive");
EXPECT_EQ(events_[0]["share_target"]["id"], 9);
EXPECT_EQ(events_[0]["transfer"]["status"], "kAwaitingLocalConfirmation");
}
TEST_F(DaemonServiceTest, AcceptRejectAndCancelReturnCommandResults) {
EXPECT_TRUE(daemon_.HandleCommand({{"command", "accept"},
{"share_target_id", 1}})["ok"]
.get<bool>());
EXPECT_EQ(service_.last_accept_target_id, 1);
EXPECT_TRUE(daemon_.HandleCommand({{"command", "reject"},
{"share_target_id", 1}})["ok"]
.get<bool>());
EXPECT_EQ(service_.last_reject_target_id, 1);
EXPECT_TRUE(daemon_.HandleCommand({{"command", "cancel"},
{"share_target_id", 1}})["ok"]
.get<bool>());
EXPECT_EQ(service_.last_cancel_target_id, 1);
}
TEST_F(DaemonServiceTest, SendFileRejectsUnknownTarget) {
nlohmann::json result = daemon_.HandleCommand(
{{"command", "send_file"}, {"share_target_id", 404}, {"path", "/tmp/x"}});
EXPECT_FALSE(result["ok"].get<bool>());
}
TEST_F(DaemonServiceTest, SendFileToKnownTargetReturnsOkForRegularFile) {
ASSERT_TRUE(
daemon_.HandleCommand({{"command", "start_discovery"}})["ok"].get<bool>());
service_.FireShareTargetDiscovered(MakeTarget(12));
const std::string path = "/tmp/nearby_daemon_service_test_file";
{
std::ofstream file(path);
file << "hello";
}
nlohmann::json result = daemon_.HandleCommand(
{{"command", "send_file"}, {"share_target_id", 12}, {"path", path}});
EXPECT_TRUE(result["ok"].get<bool>()) << result.dump();
EXPECT_EQ(service_.last_send_target_id, 12);
EXPECT_EQ(service_.last_attachment_count, 1u);
std::remove(path.c_str());
}
TEST_F(DaemonServiceTest, MalformedCommandReturnsError) {
nlohmann::json result = daemon_.HandleCommand({{"path", "/tmp/x"}});
EXPECT_FALSE(result["ok"].get<bool>());
}
} // namespace
} // namespace nearby::sharing::linux