blob: 1ac0187d852db09c2ef07c9d7068deb1f9bd7f9f [file] [log] [blame]
// Copyright 2014 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 "peerd/peer.h"
#include <string>
#include <base/time/time.h>
#include <chromeos/dbus/mock_dbus_object.h>
#include <chromeos/errors/error.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_exported_object.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "peerd/service.h"
#include "peerd/test_util.h"
using chromeos::ErrorPtr;
using chromeos::dbus_utils::DBusObject;
using chromeos::dbus_utils::ExportedObjectManager;
using dbus::Bus;
using dbus::MockBus;
using dbus::MockExportedObject;
using dbus::ObjectPath;
using peerd::Peer;
using peerd::errors::peer::kInvalidName;
using peerd::errors::peer::kInvalidNote;
using peerd::errors::peer::kInvalidTime;
using peerd::errors::peer::kInvalidUUID;
using peerd::test_util::MakeMockCompletionAction;
using std::string;
using std::unique_ptr;
using testing::AnyNumber;
using testing::Invoke;
using testing::Property;
using testing::Return;
using testing::StartsWith;
using testing::_;
namespace {
const char kPeerPath[] = "/some/path/ending/with";
const char kServicePathPrefix[] = "/some/path/ending/with/services/";
const char kServicePath[] = "/some/path/ending/with/services/1";
const char kUUID[] = "123e4567-e89b-12d3-a456-426655440000";
const char kValidName[] = "NAME";
const char kValidNote[] = "notes are long and very descriptive for people.";
} // namespace
namespace peerd {
class PeerTest : public ::testing::Test {
public:
virtual void SetUp() {
// Ignore threading concerns.
EXPECT_CALL(*mock_bus_, AssertOnOriginThread()).Times(AnyNumber());
EXPECT_CALL(*mock_bus_, AssertOnDBusThread()).Times(AnyNumber());
// Return appropriate objects when asked.
EXPECT_CALL(*mock_bus_,
GetExportedObject(Property(&ObjectPath::value,
kPeerPath)))
.WillRepeatedly(Return(peer_object_.get()));
EXPECT_CALL(*mock_bus_,
GetExportedObject(Property(&ObjectPath::value,
StartsWith(kServicePathPrefix))))
.WillRepeatedly(Return(service_object_.get()));
// Just immediately call callbacks on ExportMethod calls.
EXPECT_CALL(*peer_object_, ExportMethod(_, _, _, _))
.WillRepeatedly(Invoke(&test_util::HandleMethodExport));
EXPECT_CALL(*service_object_, ExportMethod(_, _, _, _))
.WillRepeatedly(Invoke(&test_util::HandleMethodExport));
// Ignore Unregister calls.
EXPECT_CALL(*peer_object_, Unregister()).Times(AnyNumber());
EXPECT_CALL(*service_object_, Unregister()).Times(AnyNumber());
}
unique_ptr<Peer> MakePeer() {
unique_ptr<Peer> peer{new Peer{mock_bus_, nullptr, ObjectPath{kPeerPath}}};
chromeos::ErrorPtr error;
EXPECT_TRUE(peer->RegisterAsync(
&error,
kUUID,
kValidName,
kValidNote,
base::Time::UnixEpoch() + base::TimeDelta::FromDays(1),
MakeMockCompletionAction()));
EXPECT_EQ(nullptr, error.get());
return peer;
}
void AssertBadFactoryArgs(const string& uuid,
const string& name,
const string& note,
const string& error_code) {
chromeos::ErrorPtr error;
unique_ptr<Peer> peer{
new Peer{mock_bus_, nullptr, ObjectPath{kPeerPath}}};
EXPECT_FALSE(peer->RegisterAsync(
&error,
uuid,
name,
note,
base::Time::UnixEpoch(),
MakeMockCompletionAction()));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(peerd::kPeerdErrorDomain, error_code));
}
void TestBadUUID(const string& uuid) {
AssertBadFactoryArgs(uuid, kValidName, kValidNote, kInvalidUUID);
}
scoped_refptr<MockBus> mock_bus_{new MockBus{Bus::Options{}}};
scoped_refptr<dbus::MockExportedObject> peer_object_{
new MockExportedObject{mock_bus_.get(), ObjectPath{kPeerPath}}};
scoped_refptr<dbus::MockExportedObject> service_object_{
new MockExportedObject{mock_bus_.get(), ObjectPath{kServicePath}}};
};
TEST_F(PeerTest, ShouldRejectObviouslyNotUUID) {
TestBadUUID("definitely a bad UUID");
}
TEST_F(PeerTest, ShouldRejectWrongUUIDLen) {
TestBadUUID(string(kUUID, strlen(kUUID)- 1));
}
TEST_F(PeerTest, ShouldRejectBadDashInUUID) {
string bad_uuid(kUUID);
bad_uuid[23] = 'a'; // Index 23 is the final -.
TestBadUUID(bad_uuid);
}
TEST_F(PeerTest, ShouldRejectBadCharacterInUUID) {
string bad_uuid(kUUID);
bad_uuid[bad_uuid.length() - 1] = '-';
TestBadUUID(bad_uuid);
}
TEST_F(PeerTest, ShouldRejectBadNameInFactory) {
AssertBadFactoryArgs(kUUID, "* is not allowed", kValidNote, kInvalidName);
}
TEST_F(PeerTest, ShouldRejectBadNoteInFactory) {
AssertBadFactoryArgs(kUUID, kValidName,
"notes also may not contain *", kInvalidNote);
}
TEST_F(PeerTest, ShouldRegisterWithDBus) {
auto peer = MakePeer();
EXPECT_EQ(peer->GetUUID(), kUUID);
EXPECT_EQ(peer->GetFriendlyName(), kValidName);
EXPECT_EQ(peer->GetNote(), kValidNote);
}
TEST_F(PeerTest, ShouldRejectNameTooLong) {
auto peer = MakePeer();
chromeos::ErrorPtr error;
EXPECT_FALSE(peer->SetFriendlyName(&error, string(33, 'a')));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(kPeerdErrorDomain, kInvalidName));
}
TEST_F(PeerTest, ShouldRejectNameInvalidChars) {
auto peer = MakePeer();
chromeos::ErrorPtr error;
EXPECT_FALSE(peer->SetFriendlyName(&error, "* is not allowed"));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(kPeerdErrorDomain, kInvalidName));
}
TEST_F(PeerTest, ShouldRejectNoteTooLong) {
auto peer = MakePeer();
chromeos::ErrorPtr error;
EXPECT_FALSE(peer->SetNote(&error, string(256, 'a')));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(kPeerdErrorDomain, kInvalidNote));
}
TEST_F(PeerTest, ShouldRejectNoteInvalidChars) {
auto peer = MakePeer();
chromeos::ErrorPtr error;
EXPECT_FALSE(peer->SetNote(&error, "* is also not allowed in notes"));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(kPeerdErrorDomain, kInvalidNote));
}
TEST_F(PeerTest, ShouldRejectStaleUpdate) {
auto peer = MakePeer();
chromeos::ErrorPtr error;
EXPECT_FALSE(peer->SetLastSeen(&error, base::Time::UnixEpoch()));
ASSERT_NE(nullptr, error.get());
EXPECT_TRUE(error->HasError(kPeerdErrorDomain, kInvalidTime));
}
} // namespace peerd