shill: Add persistent store support for getting/setting string lists.
BUG=chromium-os:17144
TEST=unit tests
Change-Id: Ib85935f3e53b606757aa50786d94975b1fe5109c
Reviewed-on: http://gerrit.chromium.org/gerrit/3486
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
diff --git a/crypto_provider_unittest.cc b/crypto_provider_unittest.cc
index 316b94f..b84162a 100644
--- a/crypto_provider_unittest.cc
+++ b/crypto_provider_unittest.cc
@@ -49,20 +49,20 @@
provider_.set_key_matter_file(FilePath("/some/non/existent/file"));
provider_.Init();
- EXPECT_EQ(1, provider_.cryptos_.size());
+ ASSERT_EQ(1, provider_.cryptos_.size());
EXPECT_EQ(CryptoROT47::kID, provider_.cryptos_[0]->GetID());
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
provider_.set_key_matter_file(InitKeyMatterFile(temp_dir.path()));
provider_.Init();
- EXPECT_EQ(2, provider_.cryptos_.size());
+ ASSERT_EQ(2, provider_.cryptos_.size());
EXPECT_EQ(CryptoDESCBC::kID, provider_.cryptos_[0]->GetID());
EXPECT_EQ(CryptoROT47::kID, provider_.cryptos_[1]->GetID());
provider_.set_key_matter_file(FilePath("/other/missing/file"));
provider_.Init();
- EXPECT_EQ(1, provider_.cryptos_.size());
+ ASSERT_EQ(1, provider_.cryptos_.size());
EXPECT_EQ(CryptoROT47::kID, provider_.cryptos_[0]->GetID());
}
diff --git a/glib.cc b/glib.cc
index 998aa43..95980c3 100644
--- a/glib.cc
+++ b/glib.cc
@@ -75,6 +75,14 @@
return g_key_file_get_string(key_file, group_name, key, error);
}
+gchar **GLib::KeyFileGetStringList(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error) {
+ return g_key_file_get_string_list(key_file, group_name, key, length, error);
+}
+
gboolean GLib::KeyFileHasGroup(GKeyFile *key_file,
const gchar *group_name) {
return g_key_file_has_group(key_file, group_name);
@@ -118,6 +126,14 @@
g_key_file_set_string(key_file, group_name, key, string);
}
+void GLib::KeyFileSetStringList(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar * const list[],
+ gsize length) {
+ g_key_file_set_string_list(key_file, group_name, key, list, length);
+}
+
gchar *GLib::KeyFileToData(GKeyFile *key_file,
gsize *length,
GError **error) {
diff --git a/glib.h b/glib.h
index e65eb7d..7016f0a 100644
--- a/glib.h
+++ b/glib.h
@@ -49,6 +49,12 @@
const gchar *group_name,
const gchar *key,
GError **error);
+ // g_key_file_get_string_list
+ virtual gchar **KeyFileGetStringList(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error);
// g_key_file_has_group
virtual gboolean KeyFileHasGroup(GKeyFile *key_file,
const gchar *group_name);
@@ -83,6 +89,12 @@
const gchar *group_name,
const gchar *key,
const gchar *string);
+ // g_key_file_set_string_list
+ virtual void KeyFileSetStringList(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar * const list[],
+ gsize length);
// g_key_file_to_data
virtual gchar *KeyFileToData(GKeyFile *key_file,
gsize *length,
diff --git a/key_file_store.cc b/key_file_store.cc
index cce5ea7..1fa52fb 100644
--- a/key_file_store.cc
+++ b/key_file_store.cc
@@ -9,6 +9,7 @@
using std::set;
using std::string;
+using std::vector;
namespace shill {
@@ -196,6 +197,46 @@
return true;
}
+bool KeyFileStore::GetStringList(const string &group,
+ const string &key,
+ vector<string> *value) {
+ CHECK(key_file_);
+ gsize length = 0;
+ GError *error = NULL;
+ gchar **data = glib_->KeyFileGetStringList(key_file_,
+ group.c_str(),
+ key.c_str(),
+ &length,
+ &error);
+ if (!data) {
+ LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
+ << glib_->ConvertErrorToMessage(error);
+ return false;
+ }
+ if (value) {
+ value->assign(data, data + length);
+ }
+ glib_->Strfreev(data);
+ return true;
+}
+
+bool KeyFileStore::SetStringList(const string &group,
+ const string &key,
+ const vector<string> &value) {
+ CHECK(key_file_);
+ vector<const char *> list;
+ for (vector<string>::const_iterator it = value.begin();
+ it != value.end(); ++it) {
+ list.push_back(it->c_str());
+ }
+ glib_->KeyFileSetStringList(key_file_,
+ group.c_str(),
+ key.c_str(),
+ list.data(),
+ list.size());
+ return true;
+}
+
bool KeyFileStore::GetCryptedString(const string &group,
const string &key,
string *value) {
diff --git a/key_file_store.h b/key_file_store.h
index 3e88de2..b448256 100644
--- a/key_file_store.h
+++ b/key_file_store.h
@@ -19,7 +19,7 @@
// of the key file format.
class KeyFileStore : public StoreInterface {
public:
- KeyFileStore(GLib *glib);
+ explicit KeyFileStore(GLib *glib);
virtual ~KeyFileStore();
void set_path(const FilePath &path) { path_ = path; }
@@ -50,13 +50,18 @@
virtual bool SetInt(const std::string &group,
const std::string &key,
int value);
+ virtual bool GetStringList(const std::string &group,
+ const std::string &key,
+ std::vector<std::string> *value);
+ virtual bool SetStringList(const std::string &group,
+ const std::string &key,
+ const std::vector<std::string> &value);
virtual bool GetCryptedString(const std::string &group,
const std::string &key,
std::string *value);
virtual bool SetCryptedString(const std::string &group,
const std::string &key,
const std::string &value);
-
private:
FRIEND_TEST(KeyFileStoreTest, OpenClose);
FRIEND_TEST(KeyFileStoreTest, OpenFail);
diff --git a/key_file_store_unittest.cc b/key_file_store_unittest.cc
index a206060..907ec06 100644
--- a/key_file_store_unittest.cc
+++ b/key_file_store_unittest.cc
@@ -12,6 +12,7 @@
using std::set;
using std::string;
+using std::vector;
using testing::Test;
namespace shill {
@@ -294,6 +295,121 @@
ReadKeyFile());
}
+TEST_F(KeyFileStoreTest, GetStringList) {
+ static const char kGroup[] = "string-lists";
+ static const char kKeyEmpty[] = "empty";
+ static const char kKeyEmptyValue[] = "empty-value";
+ static const char kKeyValueEmpty[] = "value-empty";
+ static const char kKeyValueEmptyValue[] = "value-empty-value";
+ static const char kKeyValues[] = "values";
+ static const char kValue[] = "value";
+ static const char kValue2[] = "value2";
+ static const char kValue3[] = "value3";
+ WriteKeyFile(base::StringPrintf("[%s]\n"
+ "%s=\n"
+ "%s=;%s\n"
+ "%s=%s;;\n"
+ "%s=%s;;%s\n"
+ "%s=%s;%s;%s\n",
+ kGroup,
+ kKeyEmpty,
+ kKeyEmptyValue, kValue,
+ kKeyValueEmpty, kValue,
+ kKeyValueEmptyValue, kValue, kValue2,
+ kKeyValues, kValue, kValue2, kValue3));
+ ASSERT_TRUE(store_.Open());
+
+ vector<string> value;
+
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyValues, &value));
+ ASSERT_EQ(3, value.size());
+ EXPECT_EQ(kValue, value[0]);
+ EXPECT_EQ(kValue2, value[1]);
+ EXPECT_EQ(kValue3, value[2]);
+
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyEmptyValue, &value));
+ ASSERT_EQ(2, value.size());
+ EXPECT_EQ("", value[0]);
+ EXPECT_EQ(kValue, value[1]);
+
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyValueEmpty, &value));
+ ASSERT_EQ(2, value.size());
+ EXPECT_EQ(kValue, value[0]);
+ EXPECT_EQ("", value[1]);
+
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyEmpty, &value));
+ ASSERT_EQ(0, value.size());
+
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyValueEmptyValue, &value));
+ ASSERT_EQ(3, value.size());
+ EXPECT_EQ(kValue, value[0]);
+ EXPECT_EQ("", value[1]);
+ EXPECT_EQ(kValue2, value[2]);
+
+ EXPECT_FALSE(store_.GetStringList("unknown-string-lists", kKeyEmpty, &value));
+ EXPECT_FALSE(store_.GetStringList(kGroup, "some-key", &value));
+ EXPECT_TRUE(store_.GetStringList(kGroup, kKeyValues, NULL));
+ ASSERT_TRUE(store_.Close());
+}
+
+TEST_F(KeyFileStoreTest, SetStringList) {
+ static const char kGroup[] = "strings";
+ static const char kKeyEmpty[] = "e";
+ static const char kKeyEmptyValue[] = "ev";
+ static const char kKeyValueEmpty[] = "ve";
+ static const char kKeyValueEmptyValue[] = "vev";
+ static const char kKeyValues[] = "v";
+ static const char kValue[] = "abc";
+ static const char kValue2[] = "pqr";
+ static const char kValue3[] = "xyz";
+ ASSERT_TRUE(store_.Open());
+ {
+ vector<string> value;
+ ASSERT_TRUE(store_.SetStringList(kGroup, kKeyEmpty, value));
+ }
+ {
+ vector<string> value;
+ value.push_back("");
+ value.push_back(kValue);
+ ASSERT_TRUE(store_.SetStringList(kGroup, kKeyEmptyValue, value));
+ }
+ {
+ vector<string> value;
+ value.push_back(kValue);
+ value.push_back("");
+ ASSERT_TRUE(store_.SetStringList(kGroup, kKeyValueEmpty, value));
+ }
+ {
+ vector<string> value;
+ value.push_back(kValue);
+ value.push_back("");
+ value.push_back(kValue2);
+ ASSERT_TRUE(store_.SetStringList(kGroup, kKeyValueEmptyValue, value));
+ }
+ {
+ vector<string> value;
+ value.push_back(kValue);
+ value.push_back(kValue2);
+ value.push_back(kValue3);
+ ASSERT_TRUE(store_.SetStringList(kGroup, kKeyValues, value));
+ }
+ ASSERT_TRUE(store_.Close());
+ EXPECT_EQ(base::StringPrintf("\n"
+ "[%s]\n"
+ "%s=\n"
+ "%s=;%s;\n"
+ "%s=%s;;\n"
+ "%s=%s;;%s;\n"
+ "%s=%s;%s;%s;\n",
+ kGroup,
+ kKeyEmpty,
+ kKeyEmptyValue, kValue,
+ kKeyValueEmpty, kValue,
+ kKeyValueEmptyValue, kValue, kValue2,
+ kKeyValues, kValue, kValue2, kValue3),
+ ReadKeyFile());
+}
+
TEST_F(KeyFileStoreTest, GetCryptedString) {
static const char kGroup[] = "crypto-group";
static const char kKey[] = "secret";
@@ -329,6 +445,7 @@
static const char kGroupC[] = "triangle";
static const char kGroupX[] = "pentagon";
static const char kKeyString[] = "color";
+ static const char kKeyStringList[] = "alternative-colors";
static const char kKeyInt[] = "area";
static const char kKeyBool[] = "visible";
static const char kValueStringA[] = "blue";
@@ -340,9 +457,11 @@
const int kValueIntBNew = 333;
WriteKeyFile(base::StringPrintf("[%s]\n"
"%s=%s\n"
+ "%s=%s;%s\n"
"%s=%d\n"
"[%s]\n"
"%s=%s\n"
+ "%s=%s;%s\n"
"%s=%d\n"
"%s=true\n"
"[%s]\n"
@@ -350,9 +469,11 @@
"%s=false\n",
kGroupA,
kKeyString, kValueStringA,
+ kKeyStringList, kValueStringB, kValueStringC,
kKeyInt, kValueIntA,
kGroupB,
kKeyString, kValueStringB,
+ kKeyStringList, kValueStringA, kValueStringC,
kKeyInt, kValueIntB,
kKeyBool,
kGroupC,
@@ -382,6 +503,18 @@
EXPECT_EQ(kValueStringC, value);
}
{
+ vector<string> value;
+ EXPECT_TRUE(store_.GetStringList(kGroupB, kKeyStringList, &value));
+ ASSERT_EQ(2, value.size());
+ EXPECT_EQ(kValueStringA, value[0]);
+ EXPECT_EQ(kValueStringC, value[1]);
+ EXPECT_TRUE(store_.GetStringList(kGroupA, kKeyStringList, &value));
+ ASSERT_EQ(2, value.size());
+ EXPECT_EQ(kValueStringB, value[0]);
+ EXPECT_EQ(kValueStringC, value[1]);
+ EXPECT_FALSE(store_.GetStringList(kGroupC, kKeyStringList, &value));
+ }
+ {
int value = 0;
EXPECT_TRUE(store_.GetInt(kGroupB, kKeyInt, &value));
EXPECT_EQ(kValueIntB, value);
@@ -414,6 +547,9 @@
EXPECT_TRUE(store_.SetBool(kGroupB, kKeyBool, false));
EXPECT_TRUE(store_.SetInt(kGroupB, kKeyInt, kValueIntBNew));
EXPECT_TRUE(store_.SetString(kGroupC, kKeyString, kValueStringCNew));
+ store_.SetStringList(kGroupB,
+ kKeyStringList,
+ vector<string>(1, kValueStringB));
EXPECT_TRUE(store_.DeleteKey(kGroupB, kKeyString));
EXPECT_FALSE(store_.DeleteKey(kGroupB, kKeyString));
@@ -425,7 +561,14 @@
EXPECT_TRUE(store_.GetString(kGroupC, kKeyString, &value));
EXPECT_EQ(kValueStringCNew, value);
}
-
+ {
+ vector<string> value;
+ EXPECT_TRUE(store_.GetStringList(kGroupB, kKeyStringList, &value));
+ ASSERT_EQ(1, value.size());
+ EXPECT_EQ(kValueStringB, value[0]);
+ EXPECT_FALSE(store_.GetStringList(kGroupA, kKeyStringList, &value));
+ EXPECT_FALSE(store_.GetStringList(kGroupC, kKeyStringList, &value));
+ }
{
int value = 0;
EXPECT_TRUE(store_.GetInt(kGroupB, kKeyInt, &value));
@@ -433,7 +576,6 @@
EXPECT_FALSE(store_.GetInt(kGroupA, kKeyInt, &value));
EXPECT_FALSE(store_.GetInt(kGroupC, kKeyInt, &value));
}
-
{
bool value = false;
EXPECT_TRUE(store_.GetBool(kGroupB, kKeyBool, &value));
@@ -446,6 +588,7 @@
ASSERT_TRUE(store_.Close());
EXPECT_EQ(base::StringPrintf("\n"
"[%s]\n"
+ "%s=%s;\n"
"%s=%d\n"
"%s=false\n"
"\n"
@@ -453,6 +596,7 @@
"%s=%s\n"
"%s=false\n",
kGroupB,
+ kKeyStringList, kValueStringB,
kKeyInt, kValueIntBNew,
kKeyBool,
kGroupC,
diff --git a/mock_glib.h b/mock_glib.h
index 8bf7218..46d714b 100644
--- a/mock_glib.h
+++ b/mock_glib.h
@@ -34,6 +34,11 @@
const gchar *group_name,
const gchar *key,
GError **error));
+ MOCK_METHOD5(KeyFileGetStringList, gchar **(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ gsize *length,
+ GError **error));
MOCK_METHOD2(KeyFileHasGroup, gboolean(GKeyFile *key_file,
const gchar *group_name));
MOCK_METHOD4(KeyFileLoadFromFile, gboolean(GKeyFile *key_file,
@@ -60,6 +65,11 @@
const gchar *group_name,
const gchar *key,
const gchar *string));
+ MOCK_METHOD5(KeyFileSetStringList, void(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ const gchar * const list[],
+ gsize length));
MOCK_METHOD3(KeyFileToData, gchar *(GKeyFile *key_file,
gsize *length,
GError **error));
diff --git a/store_interface.h b/store_interface.h
index 46a71cc..b03d3c0 100644
--- a/store_interface.h
+++ b/store_interface.h
@@ -7,6 +7,7 @@
#include <set>
#include <string>
+#include <vector>
namespace shill {
@@ -78,6 +79,19 @@
const std::string &key,
int value) = 0;
+ // Gets a string list |value| associated with |group|:|key|. Returns true on
+ // success and false on failure (including when |group|:|key| is not present
+ // in the store).
+ virtual bool GetStringList(const std::string &group,
+ const std::string &key,
+ std::vector<std::string> *value) = 0;
+
+ // Associates |group|:|key| with a string list |value|. Returns true on
+ // success, false otherwise.
+ virtual bool SetStringList(const std::string &group,
+ const std::string &key,
+ const std::vector<std::string> &value) = 0;
+
// Gets and decrypts string |value| associated with |group|:|key|. Returns
// true on success and false on failure (including when |group|:|key| is not
// present in the store).