TEST_F (Simple, GetSystem) { using namespace kdb; KDB kdb; KeySet ks; Key parentKey ("system" + testRoot, KEY_END); ks.append (Key (parentKey.getName () + "/key", KEY_END)); EXPECT_NE (kdb.get (ks, parentKey), -1); ASSERT_EQ (ks.size (), 1) << "no key stayed" << ks; ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "system/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; ASSERT_NE (kdb.set (ks, parentKey), -1); ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "system/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; kdb.close (parentKey); KeySet ks2; kdb.open (parentKey); kdb.get (ks2, parentKey); ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "system/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; }
TEST_F (Simple, GetAppendMeta) { using namespace kdb; KDB kdb; KeySet ks; ks.append (Key ("meta/key", KEY_META_NAME, KEY_END)); Key parentKey (testRoot, KEY_END); kdb.get (ks, parentKey); ASSERT_EQ (ks.size (), 1) << "no key stayed"; ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "meta/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; kdb.set (ks, parentKey); ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "meta/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; kdb.close (parentKey); KeySet ks2; kdb.open (parentKey); kdb.get (ks2, parentKey); ASSERT_EQ (ks2.size (), 0) << "got keys from freshly mounted backends"; }
int CpCommand::execute (Cmdline const & cl) { if (cl.arguments.size () != 2) { throw invalid_argument ("wrong number of arguments, 2 needed"); } KeySet conf; Key sourceKey = cl.createKey (0); if (!sourceKey.isValid ()) { throw invalid_argument ("Source given is not a valid keyname"); } Key destKey = cl.createKey (1); if (!destKey.isValid ()) { throw invalid_argument ("Destination given is not a valid keyname"); } string newDirName = destKey.getName (); kdb.get (conf, sourceKey); kdb.get (conf, destKey); KeySet tmpConf = conf; KeySet oldConf; oldConf.append (tmpConf.cut (sourceKey)); KeySet newConf; oldConf.rewind (); std::string sourceName = sourceKey.getName (); if (cl.verbose) cout << "common name: " << sourceName << endl; if (cl.recursive) { // copy all keys with new name Key k; while ((k = oldConf.next ())) { Key rk = rename_key (k, sourceName, newDirName, cl.verbose); copySingleKey (cl, rk, tmpConf, newConf); } } else { // just copy one key Key k = oldConf.next (); Key rk = rename_key (k, sourceName, newDirName, cl.verbose); copySingleKey (cl, rk, tmpConf, newConf); } newConf.append (tmpConf); // these are unrelated keys newConf.append (oldConf); // these are the original keys newConf.rewind (); kdb.set (newConf, destKey); return 0; }
/** * @brief give info about current mounted backends * * @param mountConf a keyset that contains everything below * Backends::mountpointsPath * * @return an vector of information about mounted backends */ Backends::BackendInfoVector Backends::getBackendInfo (KeySet mountConf) { std::vector<BackendInfo> ret; Key rootKey (Backends::mountpointsPath, KEY_END); Key cur; mountConf.rewind (); while ((cur = mountConf.next ())) { if (cur.isDirectBelow (rootKey)) { BackendInfo bi; Key path = mountConf.lookup (cur.getName () + "/config/path"); if (path) { bi.path = path.getString (); } Key mp = mountConf.lookup (cur.getName () + "/mountpoint"); if (mp) { bi.mountpoint = mp.getString (); } bi.name = cur.getBaseName (); ret.push_back (bi); } } return ret; }
void SpecReader::readSpecification (KeySet const & cks) { KeySet ks; Key mp; // only accept keys in 'spec' namespace for (Key k : cks) { if (k.isSpec ()) { ks.append (k); } } ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); } } }
MergeResult ThreeWayMerge::mergeKeySet(const MergeTask& task) { MergeResult result; detectConflicts (task, result); detectConflicts (task.reverse (), result, true); if (!result.hasConflicts()) return result; // TODO: test this behaviour (would probably need mocks) Key current; KeySet conflicts = result.getConflictSet(); conflicts.rewind(); while ((current = conflicts.next ())) { for (vector<MergeConflictStrategy *>::iterator it = strategies.begin (); it != strategies.end (); ++it) { (*it)->resolveConflict (task, current, result); if (!result.isConflict(current)) break; } } return result; }
TEST_F (Simple, SetSystemGetAppend2) { using namespace kdb; KDB kdb; KeySet ks; Key parentKey (testRoot, KEY_END); ks.append (Key ("system" + testRoot + "key", KEY_VALUE, "value1", KEY_END)); kdb.get (ks, parentKey); ASSERT_EQ (ks.size (), 1) << "got keys from freshly mounted backends"; ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "system/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "value1") << "string of element in keyset wrong"; kdb.set (ks, parentKey); kdb.close (parentKey); KeySet ks2; ks2.append (Key ("system" + testRoot + "key2", KEY_VALUE, "value2", KEY_END)); kdb.open (parentKey); kdb.get (ks2, parentKey); ks2.rewind (); ks2.next (); ASSERT_EQ (ks2.size (), 1) << "wrong size"; EXPECT_EQ (ks2.current ().getName (), "system/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks2.current ().getString (), "value1") << "string of element in keyset wrong"; }
MergeResult ThreeWayMerge::mergeKeySet (const MergeTask & task) { MergeResult result; detectConflicts (task, result); detectConflicts (task.reverse (), result, true); if (!result.hasConflicts ()) return result; // TODO: test this behaviour (would probably need mocks) Key current; KeySet conflicts = result.getConflictSet (); conflicts.rewind (); while ((current = conflicts.next ())) { for (auto & elem : strategies) { (elem)->resolveConflict (task, current, result); if (!result.isConflict (current)) break; } } return result; }
void RemountCommand::cloneMountpoint(Cmdline const & cl) { Key existingParent (Backends::getBasePath(existingName), KEY_END); Key newParent (Backends::getBasePath(mp), KEY_END); KeySet existingBackend = mountConf.cut(existingParent); mountConf.append(existingBackend); KeySet newBackend(existingBackend.size(), KS_END); string configPath = newParent.getName() + "/config/path"; string mpPath = newParent.getName() + "/mountpoint"; existingBackend.rewind(); while (Key current = existingBackend.next()) { Key newKey = rebaseKey (current, existingParent, newParent); newBackend.append(newKey); if (newKey.getName() == mpPath) { newKey.setString(mp); } if (newKey.getName() == configPath) { newKey.setString(cl.arguments[0]); } } mountConf.append(newBackend); }
SpecBackendBuilder SpecMountpointReader::readMountpointSpecification (KeySet const & cks) { ks = cks; mp = ks.head ().dup (); Key rmp (mp.dup ()); helper::removeNamespace (rmp); bb.setMountpoint (rmp, mountConf); processKey (mp); bb.nodes++; // count mp ks.lookup (mp, KDB_O_POP); ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); continue; } processKey (k); bb.nodes++; } bb.setBackendConfig (backendConfig); bb.useConfigFile (mp.getMeta<std::string> ("mountpoint")); return bb; }
TEST(Backend, SimpleBackend) { using namespace kdb; using namespace kdb::tools; Backend b; b.setMountpoint(Key("/", KEY_CASCADING_NAME, KEY_END), KeySet(0, KS_END)); EXPECT_EQ(b.getMountpoint(), "/"); b.addPlugin("resolver"); b.addPlugin("dump"); b.useConfigFile("abc"); EXPECT_TRUE(b.validated()); KeySet mountConfig; b.serialize(mountConfig); // outputGTest(mountConfig, "mountConfig"); mountConfig.rewind(); mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\/") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "This is a configuration for a backend, see subkeys for more information") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//config") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//config/path") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "abc") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//errorplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//errorplugins/#5#resolver#resolver#") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//getplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//getplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//getplugins/#5#dump#dump#") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//mountpoint") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "/") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//setplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//setplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//setplugins/#5#dump") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/\\//setplugins/#7#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; }
TEST_F (Simple, GetAppendCascading) { using namespace kdb; KDB kdb; KeySet ks; ks.append (Key (testRoot + "key", KEY_END)); Key parentKey (testRoot, KEY_END); std::string myRoot = testRoot.substr (0, testRoot.length () - 1); EXPECT_EQ (parentKey.getName (), myRoot); EXPECT_EQ (parentKey.getString (), ""); kdb.get (ks, parentKey); EXPECT_EQ (parentKey.getName (), myRoot); std::string fn = parentKey.getString (); EXPECT_EQ (fn.substr (fn.find_last_of ('/') + 1), "kdbFile.dump"); parentKey.setString (""); ASSERT_EQ (ks.size (), 1) << "no key stayed" << ks; ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; kdb.set (ks, parentKey); EXPECT_EQ (parentKey.getName (), myRoot); EXPECT_EQ (parentKey.getString (), ""); ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), "/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; kdb.close (parentKey); EXPECT_EQ (parentKey.getName (), myRoot); EXPECT_EQ (parentKey.getString (), ""); KeySet ks2; kdb.open (parentKey); EXPECT_EQ (parentKey.getName (), myRoot); EXPECT_EQ (parentKey.getString (), ""); kdb.get (ks2, parentKey); EXPECT_EQ (parentKey.getName (), myRoot); fn = parentKey.getString (); EXPECT_EQ (fn.substr (fn.find_last_of ('/') + 1), "kdbFile.dump"); ASSERT_EQ (ks2.size (), 0) << "got keys from freshly mounted backends"; }
void MetaMergeStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result) { conflictKey.rewindMeta(); Key currentMeta; string baseLookup = rebasePath (conflictKey, task.mergeRoot, task.baseParent); string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent); string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent); Key baseKey = task.base.lookup(baseLookup); Key ourKey = task.ours.lookup(ourLookup); Key theirKey = task.theirs.lookup(theirLookup); Key root ("user/", KEY_END); KeySet baseMeta = getMetaKeys (baseKey); KeySet ourMeta = getMetaKeys (ourKey); KeySet theirMeta = getMetaKeys (theirKey); MergeTask metaTask(BaseMergeKeys (baseMeta, root), OurMergeKeys (ourMeta, root), TheirMergeKeys (theirMeta, root), root); MergeResult metaResult = innerMerger.mergeKeySet(metaTask); KeySet mergedMeta = metaResult.getMergedKeys(); Key current; mergedMeta.rewind(); while ((current = mergedMeta.next())) { string metaName = current.getName().substr(string("user/").length()); conflictKey.setMeta(metaName, current.getString()); } ConflictOperation ourOperation = getOurConflictOperation(conflictKey); ConflictOperation theirOperation = getTheirConflictOperation(conflictKey); if (!metaResult.hasConflicts ()) { if (ourOperation == CONFLICT_META && theirOperation == CONFLICT_META) { // TODO: addConflict deletes the key content // without this strategy restoring the value the value would be lost // this happens only for CONFLICT_META <--> CONFLICT_META conflicts // add a test for this behaviour copyKeyValue(ourKey, conflictKey); result.resolveConflict (conflictKey); result.addMergeKey (conflictKey); } } }
TEST(MergeResult, ResolveConflictDeletesConflictMeta) { using namespace kdb; using namespace kdb::tools; Backend b("my_backend", "/"); b.addPlugin("resolver"); b.addPlugin("dump"); b.validated(); Key rootKey(Backends::mountpointsPath, KEY_END); KeySet mountConfig; b.serialise(rootKey, mountConfig); // outputGTest(mountConfig, "mountConfig"); mountConfig.rewind(); mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "serialised Backend") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/errorplugins") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/errorplugins/#5#resolver#resolver#") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/getplugins") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/getplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/getplugins/#5#dump#dump#") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/mountpoint") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "/") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/setplugins") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/setplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/setplugins/#5#dump") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_TRUE(mountConfig.current().getName() == "system/elektra/mountpoints/my_backend/setplugins/#7#resolver") << "name of element in keyset wrong"; EXPECT_TRUE(mountConfig.current().getString() == "") << "string of element in keyset wrong"; }
TEST_F (Simple, GetAppendNamespaces) { using namespace kdb; for (size_t i = 0; i < namespaces.size (); ++i) { KDB kdb; KeySet ks; ks.append (Key (namespaces[i].name + testRoot + "key", KEY_END)); kdb.get (ks, testRoot); ASSERT_EQ (ks.size (), 1) << "did not got key appended first with namespace " << namespaces[i].name; ks.rewind (); ks.next (); EXPECT_EQ (ks.current ().getName (), namespaces[i].name + "/tests/kdb/key") << "name of element in keyset wrong"; EXPECT_EQ (ks.current ().getString (), "") << "string of element in keyset wrong"; } }
TEST_F(ThreeWayMergeTest, CascadingParentsCauseNoCascadingKeys) { Key root("/", KEY_END); MergeResult result = merger.mergeKeySet(MergeTask(BaseMergeKeys(base, Key("/parentb", KEY_END)), OurMergeKeys(ours, Key("/parento", KEY_END)), TheirMergeKeys (theirs, Key("/parentt", KEY_END)), root)); EXPECT_FALSE(result.hasConflicts()) << "Invalid conflict detected"; Key current; KeySet merged = result.getMergedKeys (); merged.rewind(); while ((current = merged.next ())) { EXPECT_FALSE(current.getNamespace() == "/"); } }
void SpecReader::readSpecification (KeySet const & cks) { KeySet ks (cks); Key mp; ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); } } }
TEST_F(ThreeWayMergeTest, EqualKeySetsWontCauseSync) { unsyncKeys(ours); unsyncKeys(theirs); unsyncKeys(base); MergeResult result = merger.mergeKeySet (base, ours, theirs, ourParent); EXPECT_FALSE(result.hasConflicts()) << "Invalid conflict detected"; KeySet merged = result.getMergedKeys(); Key current; merged.rewind(); while ((current = merged.next ())) { EXPECT_FALSE(current.needSync()); } }
int TestCommand::execute(Cmdline const& cl) { if (cl.arguments.size() < 1) { throw invalid_argument ("need at least one argument"); } // do a basic check on every argument for (size_t i=1; i<cl.arguments.size(); ++i) { string name = " "; name += cl.arguments[i]; name += " "; if (testNames.find(name) == std::string::npos) { throw invalid_argument ("test name " + cl.arguments[i] + " does not exist in:" + testNames); } } printWarnings(cerr, root); root = cl.createKey(0); KDB kdb; KeySet original; kdb.get(original, root); original.rewind(); doTests(cl.arguments); cerr << "We got " << nrError << " errors in " << nrTest << " testcases." << endl; cout << "Test suite is now finished." << endl; cout << "Now restoring the original keyset." << endl; kdb.set(original, root); printWarnings(cerr, root); return nrError; }
void serialise(ostream &ofs, KeySet & output) { ofs << '{' << endl; output.rewind(); while (Key k = output.next()) { ofs << "\t{" << endl; ofs << "\t\t" << k.getName() << " = " << k.getString() << endl; k.rewindMeta(); while (const Key m = k.nextMeta()) { ofs << "\t\t{" << endl; ofs << "\t\t\t" << m.getName() << " = " << m.getString() << endl; ofs << "\t\t}" << endl; } ofs << "\t}" << endl; } ofs << '}' << endl; }
TEST(Backend, SimpleBackendWithConf) { using namespace kdb; using namespace kdb::tools; Backend b; b.setMountpoint(Key("user/somewhere", KEY_END), KeySet(0, KS_END)); EXPECT_EQ(b.getMountpoint(), "user/somewhere"); KeySet backendConf(5, *Key("system/globalConf", KEY_VALUE, "for everywhere", KEY_END), *Key("system/other_global_conf", KEY_VALUE, "more", KEY_END), KS_END); b.setBackendConfig(backendConf); KeySet resConf(5, *Key("user/res_conf", KEY_VALUE, "do resolving", KEY_END), *Key("user/other_res_conf", KEY_VALUE, "do resolving too", KEY_END), KS_END); b.addPlugin("resolver", resConf); KeySet dumpConf(5, *Key("user/file_format", KEY_VALUE, "1", KEY_END), *Key("user/other_dump_conf", KEY_VALUE, "some dump config", KEY_END), KS_END); b.addPlugin("dump", dumpConf); b.useConfigFile("abc"); EXPECT_TRUE(b.validated()); KeySet mountConfig; b.serialize(mountConfig); // outputGTest(mountConfig, "mountConfig"); mountConfig.rewind(); mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "This is a configuration for a backend, see subkeys for more information") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/config") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/config/globalConf") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "for everywhere") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/config/other_global_conf") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "more") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/config/path") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "abc") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/errorplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/errorplugins/#5#resolver#resolver#") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/errorplugins/#5#resolver#resolver#/config") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/errorplugins/#5#resolver#resolver#/config/other_res_conf") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "do resolving too") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/errorplugins/#5#resolver#resolver#/config/res_conf") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "do resolving") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins/#5#dump#dump#") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins/#5#dump#dump#/config") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins/#5#dump#dump#/config/file_format") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "1") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/getplugins/#5#dump#dump#/config/other_dump_conf") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "some dump config") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/mountpoint") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "user/somewhere") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/setplugins") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/setplugins/#0#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/setplugins/#5#dump") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; mountConfig.next(); EXPECT_EQ(mountConfig.current().getName(), "system/elektra/mountpoints/user\\/somewhere/setplugins/#7#resolver") << "name of element in keyset wrong"; EXPECT_EQ(mountConfig.current().getString(), "") << "string of element in keyset wrong"; }
int MvCommand::execute (Cmdline const & cl) { if (cl.arguments.size () != 2) { throw invalid_argument ("wrong number of arguments, 2 needed"); } KeySet conf; Key sourceKey = cl.createKey (0, false); Key destKey = cl.createKey (1, false); string newDirName = destKey.getName (); Key root = tools::helper::commonKeyName (sourceKey, destKey); if (cl.verbose) std::cout << "using common basename: " << root.getName () << std::endl; kdb.get (conf, root); KeySet tmpConf = conf; KeySet oldConf; oldConf.append (tmpConf.cut (sourceKey)); std::string sourceName = sourceKey.getName (); if (!oldConf.size ()) { std::cerr << "No key to copy found below '" << sourceName << "'" << std::endl; return 11; } KeySet newConf; Key k; oldConf.rewind (); if (cl.recursive) { while ((k = oldConf.next ())) { newConf.append (rename_key (k, sourceName, newDirName, cl.verbose)); } } else { // just rename one key k = oldConf.next (); if (k != sourceKey) { cerr << "First key found " << k.getName () << " does not exactly match given key " << sourceKey.getName () << ", aborting (use -r to move hierarchy)\n"; return 11; } newConf.append (rename_key (k, sourceName, newDirName, cl.verbose)); } newConf.append (tmpConf); // these are unrelated keys // drop the original configuration newConf.rewind (); if (cl.verbose) { cout << "Will write out:" << endl; cout << newConf; } kdb.set (newConf, root); printWarnings (cerr, root); return 0; }
int main() { KeySet ours; KeySet theirs; KeySet base; // the root of the subtree containing our keys (i.e. our side of the merge) Key oursRoot ("user/ours", KEY_END); // the root of the subtree containing their keys (i.e. their side of the merge) Key theirsRoot ("user/theirs", KEY_END); // the root of the subtree containing the base keys (i.e. the common ancestor of the merge) Key baseRoot ("user/base", KEY_END); // the root of the subtree that will contain the merge result Key resultRoot ("user/result", KEY_END); // Step 1: retrieve clean KeySets containing only those // keys that should be merged. This is a bit trickier than // it seems at first. Have a look at the documentation of kdbGet // for detailed information // things to note: // * use blocks with local KDB instances so we don't have to worry about // writing the keys back // * remove the root key itself from the result KeySet because it usually // contains the mounted filename and cannot be merged anyway // Also have a look at the documentation of kdbSet() // (http://doc.libelektra.org/api/latest/html/group__kdb.html#ga11436b058408f83d303ca5e996832bcf). // The merging framework can also be used to resolve conflicts resulting from // concurrent calls to kdbSet() as described in the example of kdbSet(). { KDB lkdb; lkdb.get (ours, oursRoot); ours = ours.cut (oursRoot); ours.lookup(oursRoot, KDB_O_POP); lkdb.get (theirs, theirsRoot); theirs = theirs.cut (theirsRoot); theirs.lookup(theirsRoot, KDB_O_POP); lkdb.get (base, baseRoot); base = base.cut (baseRoot); base.lookup(baseRoot, KDB_O_POP); } // Step 2: Make sure that no keys reside below the intended merge result root // Usually the merge can be either aborted if this is the case or the existing // keys can be overwritten. KeySet resultKeys; kdb::KDB kdb; kdb.get (resultKeys, resultRoot); KeySet discard = resultKeys.cut (resultRoot); if (discard.size () != 0) { // handle existing keys below the result root return -1; } ThreeWayMerge merger; // Step 3: Decide which resolution strategies to use. The strategies are registered // with the merge and applied in order as soon as a conflict is detected. If a strategy // marks a conflict as resolved, no further strategies are consulted. Therefore the order // in which they are registered is absolutely crucial. With this chaining the strategies // remain simple, but can be combined to powerful resolution strategies. // Have a look at the strategy documentation for further details on what they do and how they work. // The unit tests also provide insight into how the strategies work. // In order to simplify the initialization, predefined merge configurations exist. // in this example we first resolve all the keys that can be automatically // resolved (e.g. only one side was modified). This is exactly the use case of the // AutoMergeConfiguration. AutoMergeConfiguration configuration; configuration.configureMerger(merger); // Step 4: Perform the actual merge MergeResult result = merger.mergeKeySet ( MergeTask (BaseMergeKeys (base, baseRoot), OurMergeKeys (ours, oursRoot), TheirMergeKeys (theirs, theirsRoot), resultRoot)); // Step 5: work with the result. The merger will return an object containing information // about the merge result. if (!result.hasConflicts ()) { // output some statistical information cout << result.getMergedKeys().size() << " keys in the result" << endl; cout << result.getNumberOfEqualKeys() << " keys were equal" << endl; cout << result.getNumberOfResolvedKeys() << " keys were resolved" << endl; // write the result resultKeys.append(result.getMergedKeys()); kdb.set (resultKeys, resultRoot); return 0; } else { KeySet conflicts = result.getConflictSet(); cerr << conflicts.size() << " conflicts were detected that could not be resolved automatically:" << endl; conflicts.rewind(); Key current; while ((current = conflicts.next())) { // For each unresolved conflict there is a conflict key in the merge result. // This conflict key contains meta information about the reason of the conflict. // In particular the metakeys conflict/operation/our and conflict/operation/their contain // the operations done on our version of the key and their version of the key relative to // the base version of the key. string ourConflict = current.getMeta<string> ("conflict/operation/our"); string theirConflict = current.getMeta<string> ("conflict/operation/their"); cerr << current << endl; cerr << "ours: " << ourConflict << ", theirs: " << theirConflict << endl; cerr << endl; } cerr << "Merge unsuccessful." << endl; return -1; } }
void TestCommand::doNamingTest () { vector<string> teststrings; teststrings.push_back ("keyname"); teststrings.push_back ("deep/below/keyname"); teststrings.push_back ("keyname with spaces"); teststrings.push_back ("deep/belowkeyname with spaces"); teststrings.push_back (" a very long value with many spaces and basically very very long, but only text "); for (int i = 1; i < 256; ++i) teststrings.back () += "/ very very long, but only text ... "; teststrings.push_back ("ascii umlauts !\"§$%&/()=?`\\}][{"); teststrings.push_back ("utf8 umlauts ¸¬½¼³²¹ł€¶øæßð𳽫»¢“”nµ─·"); teststrings.push_back ("all chars:"); for (int i = 1; i < 256; ++i) teststrings.back ().push_back (i); teststrings.push_back ("€"); for (int i = 1; i < 256; ++i) { if (i == '.') continue; string s; s.push_back (i); teststrings.push_back (s); } for (auto & teststring : teststrings) { { KDB kdb; Key t = root.dup (); t.addBaseName (teststring); KeySet basic; basic.append (t); KeySet test; kdb.get (test, root); kdb.set (basic, root); } { KDB kdb; KeySet test; kdb.get (test, root); test.rewind (); Key res = test.next (); nrTest++; if (!res) { nrError++; cerr << "Naming test failed (no key in keyset)" << endl; continue; } nrTest++; Key cmp = root.dup (); cmp.addBaseName (teststring); if (res != cmp) { nrError++; cerr << "Naming test failed (name is not equal)" << endl; cerr << "We got: \"" << res.getName () << "\"" << endl; cerr << "We wanted: \"" << cmp.getName () << "\"" << endl; } } } }