blob: 3d86703d793ae896dc48182a0151ae467a250415 [file] [log] [blame]
// Copyright (c) 2012 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 "shill/dbus_adaptor.h"
#include <map>
#include <string>
#include <vector>
#include <dbus-c++/dbus.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "shill/event_dispatcher.h"
#include "shill/key_value_store.h"
#include "shill/manager.h"
#include "shill/mock_control.h"
#include "shill/mock_device.h"
#include "shill/mock_glib.h"
#include "shill/mock_profile.h"
#include "shill/mock_property_store.h"
#include "shill/mock_service.h"
#include "shill/property_store_unittest.h"
using std::map;
using std::string;
using std::vector;
using ::testing::_;
using ::testing::ContainerEq;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::StrEq;
using ::testing::Test;
namespace shill {
class DBusAdaptorTest : public PropertyStoreTest {
public:
DBusAdaptorTest()
: ex_bool_(true),
ex_byte_(0xff),
ex_bytearrays_{ByteArray()},
ex_uint16_(65535),
ex_uint16s_{ex_uint16_},
ex_uint32_(2000000),
ex_uint64_(8589934591LL),
ex_int16_(-32768),
ex_int32_(-65536),
ex_path_("/"),
ex_paths_{ex_path_},
ex_string_("something"),
ex_stringmap_{{ex_string_, ex_string_}},
ex_stringmaps_{ex_stringmap_},
ex_strings_(1, ex_string_),
bool_v_(DBusAdaptor::BoolToVariant(ex_bool_)),
byte_v_(DBusAdaptor::ByteToVariant(ex_byte_)),
bytearrays_v_(DBusAdaptor::ByteArraysToVariant(ex_bytearrays_)),
int16_v_(DBusAdaptor::Int16ToVariant(ex_int16_)),
int32_v_(DBusAdaptor::Int32ToVariant(ex_int32_)),
path_v_(DBusAdaptor::PathToVariant(ex_path_)),
paths_v_(DBusAdaptor::PathsToVariant(ex_paths_)),
string_v_(DBusAdaptor::StringToVariant(ex_string_)),
stringmap_v_(DBusAdaptor::StringmapToVariant(ex_stringmap_)),
stringmaps_v_(DBusAdaptor::StringmapsToVariant(ex_stringmaps_)),
strings_v_(DBusAdaptor::StringsToVariant(ex_strings_)),
uint16_v_(DBusAdaptor::Uint16ToVariant(ex_uint16_)),
uint16s_v_(DBusAdaptor::Uint16sToVariant(ex_uint16s_)),
uint32_v_(DBusAdaptor::Uint32ToVariant(ex_uint32_)),
uint64_v_(DBusAdaptor::Uint64ToVariant(ex_uint64_)),
device_(new MockDevice(control_interface(),
dispatcher(),
metrics(),
manager(),
"mock",
"addr0",
0)),
service_(new MockService(control_interface(),
dispatcher(),
metrics(),
manager())) {}
virtual ~DBusAdaptorTest() {}
protected:
bool ex_bool_;
uint8_t ex_byte_;
ByteArrays ex_bytearrays_;
uint16_t ex_uint16_;
vector<uint16_t> ex_uint16s_;
uint32_t ex_uint32_;
uint64_t ex_uint64_;
int16_t ex_int16_;
int32_t ex_int32_;
::DBus::Path ex_path_;
vector<::DBus::Path> ex_paths_;
string ex_string_;
map<string, string> ex_stringmap_;
vector<map<string, string>> ex_stringmaps_;
vector<string> ex_strings_;
::DBus::Variant bool_v_;
::DBus::Variant byte_v_;
::DBus::Variant bytearrays_v_;
::DBus::Variant int16_v_;
::DBus::Variant int32_v_;
::DBus::Variant path_v_;
::DBus::Variant paths_v_;
::DBus::Variant string_v_;
::DBus::Variant stringmap_v_;
::DBus::Variant stringmaps_v_;
::DBus::Variant strings_v_;
::DBus::Variant uint16_v_;
::DBus::Variant uint16s_v_;
::DBus::Variant uint32_v_;
::DBus::Variant uint64_v_;
DeviceRefPtr device_;
ServiceRefPtr service_;
};
TEST_F(DBusAdaptorTest, Conversions) {
EXPECT_EQ(0, PropertyStoreTest::kBoolV.reader().get_bool());
EXPECT_EQ(ex_bool_, bool_v_.reader().get_bool());
EXPECT_EQ(0, PropertyStoreTest::kByteV.reader().get_byte());
EXPECT_EQ(ex_byte_, byte_v_.reader().get_byte());
EXPECT_TRUE(ex_bytearrays_ == bytearrays_v_.operator ByteArrays());
EXPECT_EQ(0, PropertyStoreTest::kUint16V.reader().get_uint16());
EXPECT_EQ(ex_uint16_, uint16_v_.reader().get_uint16());
EXPECT_EQ(0, PropertyStoreTest::kInt16V.reader().get_int16());
EXPECT_EQ(ex_int16_, int16_v_.reader().get_int16());
EXPECT_EQ(0, PropertyStoreTest::kUint32V.reader().get_uint32());
EXPECT_EQ(ex_uint32_, uint32_v_.reader().get_uint32());
EXPECT_EQ(0, PropertyStoreTest::kUint64V.reader().get_uint64());
EXPECT_EQ(ex_uint64_, uint64_v_.reader().get_uint64());
EXPECT_EQ(0, PropertyStoreTest::kInt32V.reader().get_int32());
EXPECT_EQ(ex_int32_, int32_v_.reader().get_int32());
EXPECT_EQ(ex_path_, path_v_.reader().get_path());
EXPECT_EQ(ex_path_, paths_v_.operator vector<::DBus::Path>()[0]);
EXPECT_EQ(string(""), PropertyStoreTest::kStringV.reader().get_string());
EXPECT_EQ(ex_string_, string_v_.reader().get_string());
EXPECT_THAT(ex_stringmap_,
ContainerEq(stringmap_v_.operator map<string, string>()));
EXPECT_THAT(ex_strings_,
ContainerEq(strings_v_.operator vector<string>()));
EXPECT_THAT(
ex_stringmaps_,
ContainerEq(stringmaps_v_.operator vector<map<string, string>>()));
EXPECT_THAT(ex_uint16s_,
ContainerEq(uint16s_v_.operator vector<uint16_t>()));
}
TEST_F(DBusAdaptorTest, Signatures) {
EXPECT_TRUE(DBusAdaptor::IsBool(bool_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsByteArrays(bytearrays_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsByte(byte_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsInt16(int16_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsInt32(int32_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsPath(path_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsPaths(paths_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsString(string_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsStringmap(stringmap_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsStrings(strings_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsUint16(uint16_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsUint16s(uint16s_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsUint32(uint32_v_.signature()));
EXPECT_TRUE(DBusAdaptor::IsUint64(uint64_v_.signature()));
EXPECT_FALSE(DBusAdaptor::IsBool(byte_v_.signature()));
EXPECT_FALSE(DBusAdaptor::IsStrings(string_v_.signature()));
}
template <typename T>
class DBusAdaptorTypedTest : public DBusAdaptorTest {
protected:
T* property() { return &property_; }
private:
T property_{}; // value-initialize primitives
};
TYPED_TEST_CASE(DBusAdaptorTypedTest, PropertyStoreTest::PropertyTypes);
TYPED_TEST(DBusAdaptorTypedTest, GetProperties) {
MockPropertyStore store;
const string kPropertyName("some property");
PropertyStoreTest::RegisterProperty(&store, kPropertyName, this->property());
map<string, ::DBus::Variant> properties;
::DBus::Error error;
EXPECT_TRUE(DBusAdaptor::GetProperties(store, &properties, &error));
EXPECT_TRUE(ContainsKey(properties, kPropertyName));
}
TEST_F(DBusAdaptorTest, SetProperty) {
MockPropertyStore store;
::DBus::Error e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12;
EXPECT_CALL(store, Contains(_)).WillRepeatedly(Return(true));
EXPECT_CALL(store, SetBoolProperty("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetInt16Property("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetInt32Property("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetStringProperty("", _, _))
.WillOnce(Return(true));
EXPECT_CALL(store, SetStringmapProperty("", _, _))
.WillOnce(Return(true));
EXPECT_CALL(store, SetStringsProperty("", _, _))
.WillOnce(Return(true));
EXPECT_CALL(store, SetUint8Property("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetUint16Property("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetUint16sProperty("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetUint32Property("", _, _)).WillOnce(Return(true));
EXPECT_CALL(store, SetUint64Property("", _, _)).WillOnce(Return(true));
string string_path("/false/path");
::DBus::Path path(string_path);
::DBus::Variant path_v = DBusAdaptor::PathToVariant(path);
EXPECT_CALL(store, SetStringProperty("", StrEq(string_path), _))
.WillOnce(Return(true));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", bool_v_, &e1));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", path_v, &e2));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", string_v_, &e3));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", strings_v_, &e4));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", int16_v_, &e5));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", int32_v_, &e6));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", uint16_v_, &e7));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", uint16s_v_, &e8));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", uint32_v_, &e9));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", uint64_v_, &e10));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", stringmap_v_, &e11));
EXPECT_TRUE(DBusAdaptor::SetProperty(&store, "", byte_v_, &e12));
}
// SetProperty method should propagate failures. This should happen
// even if error isn't set. (This is to accomodate the fact that, if
// the property already has the desired value, the store will return
// false, without setting an error.)
TEST_F(DBusAdaptorTest, SetPropertyFailure) {
MockPropertyStore store;
::DBus::Error e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12;
EXPECT_CALL(store, Contains(_)).WillRepeatedly(Return(false));
EXPECT_CALL(store, SetBoolProperty("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetInt16Property("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetInt32Property("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetStringProperty("", _, _))
.WillOnce(Return(false));
EXPECT_CALL(store, SetStringmapProperty("", _, _))
.WillOnce(Return(false));
EXPECT_CALL(store, SetStringsProperty("", _, _))
.WillOnce(Return(false));
EXPECT_CALL(store, SetUint8Property("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetUint16Property("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetUint16sProperty("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetUint32Property("", _, _)).WillOnce(Return(false));
EXPECT_CALL(store, SetUint64Property("", _, _)).WillOnce(Return(false));
string string_path("/false/path");
::DBus::Path path(string_path);
::DBus::Variant path_v = DBusAdaptor::PathToVariant(path);
EXPECT_CALL(store, SetStringProperty("", StrEq(string_path), _))
.WillOnce(Return(false));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", bool_v_, &e1));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", path_v, &e2));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", string_v_, &e3));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", strings_v_, &e4));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", int16_v_, &e5));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", int32_v_, &e6));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", uint16_v_, &e7));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", uint16s_v_, &e8));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", uint32_v_, &e9));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", uint64_v_, &e10));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", stringmap_v_, &e11));
EXPECT_FALSE(DBusAdaptor::SetProperty(&store, "", byte_v_, &e12));
}
void SetError(const string& /*name*/, Error* error) {
error->Populate(Error::kInvalidProperty);
}
TEST_F(DBusAdaptorTest, ClearProperty) {
MockPropertyStore store;
::DBus::Error e1, e2;
EXPECT_CALL(store, ClearProperty("valid property", _)).
WillOnce(Return(true));
EXPECT_CALL(store, ClearProperty("invalid property", _)).
WillOnce(DoAll(Invoke(SetError),
Return(false)));
EXPECT_TRUE(DBusAdaptor::ClearProperty(&store, "valid property", &e1));
EXPECT_FALSE(DBusAdaptor::ClearProperty(&store, "invalid property", &e2));
}
TEST_F(DBusAdaptorTest, ArgsToKeyValueStore) {
map<string, ::DBus::Variant> args;
KeyValueStore args_kv;
Error error;
const bool kBool = true;
const char kBoolKey[] = "bool_arg";
args[kBoolKey].writer().append_bool(kBool);
const int32_t kInt32 = 123;
const char kInt32Key[] = "int32_arg";
args[kInt32Key].writer().append_int32(kInt32);
const char kString[] = "string";
const char kStringKey[] = "string_arg";
args[kStringKey].writer().append_string(kString);
const map<string, string> kStringmap{ { "key0", "value0" } };
const char kStringmapKey[] = "stringmap_key";
DBus::MessageIter writer = args[kStringmapKey].writer();
writer << kStringmap;
const vector<string> kStrings{ "string0", "string1" };
const char kStringsKey[] = "strings_key";
writer = args[kStringsKey].writer();
writer << kStrings;
map<string, ::DBus::Variant> variant_map;
const char kVariantMapSubKey[] = "map_sub_key";
variant_map[kVariantMapSubKey] = DBusAdaptor::BoolToVariant(true);
const char kVariantMapKey[] = "map_key";
writer = args[kVariantMapKey].writer();
writer << variant_map;
DBusAdaptor::ArgsToKeyValueStore(args, &args_kv, &error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_EQ(kBool, args_kv.GetBool(kBoolKey));
EXPECT_EQ(kInt32, args_kv.GetInt(kInt32Key));
EXPECT_EQ(kString, args_kv.GetString(kStringKey));
EXPECT_EQ(kStringmap, args_kv.GetStringmap(kStringmapKey));
EXPECT_EQ(kStrings, args_kv.GetStrings(kStringsKey));
KeyValueStore property_map;
property_map.SetBool(kVariantMapSubKey, true);
EXPECT_EQ(property_map, args_kv.GetKeyValueStore(kVariantMapKey));
}
TEST_F(DBusAdaptorTest, KeyValueStoreToVariant) {
const char kStringmapKey[] = "StringmapKey";
const map<string, string> kStringmapValue{ { "key", "value" } };
const char kStringsKey[] = "StringsKey";
const vector<string> kStringsValue{ "string0", "string1" };
const char kStringKey[] = "StringKey";
const char kStringValue[] = "StringValue";
const char kBoolKey[] = "BoolKey";
const bool kBoolValue = true;
KeyValueStore store;
store.SetStringmap(kStringmapKey, kStringmapValue);
store.SetStrings(kStringsKey, kStringsValue);
store.SetString(kStringKey, kStringValue);
store.SetBool(kBoolKey, kBoolValue);
DBus::Variant var = DBusAdaptor::KeyValueStoreToVariant(store);
ASSERT_TRUE(DBusAdaptor::IsKeyValueStore(var.signature()));
DBusPropertiesMap props = var.operator DBusPropertiesMap();
// Sanity test the result.
EXPECT_EQ(4, props.size());
map<string, string> stringmap_value;
EXPECT_TRUE(
DBusProperties::GetStringmap(props, kStringmapKey, &stringmap_value));
EXPECT_EQ(kStringmapValue, stringmap_value);
vector<string> strings_value;
EXPECT_TRUE(DBusProperties::GetStrings(props, kStringsKey, &strings_value));
EXPECT_EQ(kStringsValue, strings_value);
string string_value;
EXPECT_TRUE(DBusProperties::GetString(props, kStringKey, &string_value));
EXPECT_EQ(kStringValue, string_value);
bool bool_value = !kBoolValue;
EXPECT_TRUE(DBusProperties::GetBool(props, kBoolKey, &bool_value));
EXPECT_EQ(kBoolValue, bool_value);
}
TEST_F(DBusAdaptorTest, SanitizePathElement) {
EXPECT_EQ("0Ab_y_Z_9_", DBusAdaptor::SanitizePathElement("0Ab/y:Z`9{"));
EXPECT_EQ("aB_f_0_Y_z", DBusAdaptor::SanitizePathElement("aB-f/0@Y[z"));
}
} // namespace shill