Commit 194e92ae authored by Denis Zalevskiy's avatar Denis Zalevskiy

Merge pull request #18 from nemomobile/staging

Consider backup as failed if any unit is failed
parents 42948f9b ae46fe44
......@@ -23,5 +23,4 @@ units/vault-*
*.moc
tests/tests.xml
tests/*_unit.cpp
tests/*_vault_test
src/config.hpp
......@@ -47,6 +47,7 @@ public:
QString script() const;
inline QVariantMap data() const { return m_data; }
bool isLocal() const { return is(m_data.value("local", QVariant(false))); }
private:
QVariantMap m_data;
};
......
......@@ -64,10 +64,18 @@ public:
Q_INVOKABLE void backup(const QString &home, const QStringList &units, const QString &message)
{
debug::debug("Backup: home", home);
m_vault->backup(home, units, message, [this](const QString unit, const QString &status) {
auto res = m_vault->backup(home, units, message, [this](const QString unit, const QString &status) {
emit progress(Vault::Backup, {{"unit", unit}, {"status", status}});
});
emit done(Vault::Backup, QVariantMap());
if (res.failedUnits.size() == 0) {
emit done(Vault::Backup, QVariantMap());
} else {
QVariantMap info{{"msg", "Backup of some units is failed"}
, {"reason", "Backup"}
, {"succeeded", res.succededUnits}
, {"failed", res.failedUnits}};
emit error(Vault::Backup, info);
}
}
QStringList snapshots() const
......
......@@ -180,8 +180,12 @@ int Vault::execute(const QVariantMap &options)
if (!options.contains("data")) {
error::raise({{"action", action}, {"msg", "Needs data"}});
}
qDebug()<<parseKvPairs(options.value("data").toString());
vault.registerConfig(parseKvPairs(options.value("data").toString()));
auto data = parseKvPairs(str(options["data"]));
if (options.contains("unit"))
data["unit"] = options["unit"];
data["local"] = true;
debug::info("Register local unit:", data);
vault.registerConfig(data);
} else if (action == "unregister") {
if (!options.contains("unit")) {
error::raise({{"action", action}, {"msg", "Needs unit name"}});
......@@ -337,8 +341,13 @@ void Vault::setup(const QVariantMap *config)
} else if (config) {
debug::info("Repository initialization is requested");
if (os::path::exists(m_path))
error::raise({{"msg", "Vault dir already exists, can't create"}, {"path", m_path}});
if (os::path::exists(m_path)) {
QDir d(m_path);
if (!d.entryList(QDir::NoDotAndDotDot).isEmpty())
error::raise({
{"msg", "Vault dir already exists and not empty"}
, {"path", m_path}});
}
try {
createRepo();
......@@ -396,7 +405,6 @@ Vault::Result Vault::backup(const QString &home, const QStringList &units, const
debug::info("Backup units", units, ", home", home);
auto l = lock();
Result res;
res.failedUnits << units;
if (!os::path::isDir(home)) {
qWarning("Home is not a dir: %s", qPrintable(home));
......@@ -408,6 +416,7 @@ Vault::Result Vault::backup(const QString &home, const QStringList &units, const
};
resetMaster();
Gittin::Commit head = Gittin::Branch(&m_vcs, "master").head();
QStringList usedUnits = units;
if (units.isEmpty()) {
......@@ -419,12 +428,14 @@ Vault::Result Vault::backup(const QString &home, const QStringList &units, const
}
for (const QString &unit: usedUnits) {
if (backupUnit(home, unit, progress)) {
res.failedUnits.removeOne(unit);
res.succededUnits << unit;
} else {
res.failedUnits << unit;
break;
}
}
if (res.succededUnits.size()) {
if (res.succededUnits.size() == usedUnits.size()) {
QString timeTag = QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddTHH-mm-ss.zzzZ");
qDebug()<<timeTag<<message;
QString msg = message.isEmpty() ? timeTag : message + '\n' + timeTag;
......@@ -434,7 +445,8 @@ Vault::Result Vault::backup(const QString &home, const QStringList &units, const
commit.addNote(message);
tagSnapshot(timeTag);
} else {
debug::warning("There is no succeeded units, no tag");
debug::warning("Some unit backup is failed, no tag");
reset(head.sha());
}
return res;
}
......
......@@ -225,19 +225,24 @@ bool Vault::update(const QMap<QString, Unit> &src)
bool Vault::update(const QVariantMap &src)
{
bool updated = false;
QStringList units = m_config.units().keys();
auto before = m_config.units();
for (auto i = src.begin(); i != src.end(); ++i) {
if (set(i.value().toMap())) {
updated = true;
}
}
for (const QString &n: units) {
if (!src.contains(n)) {
if (!rm(n)) {
error::raise({{"msg", n + " is not removed??"}});
}
updated = true;
}
// remove local copy of the global unit if there is no global
// counterpart
for (auto it = before.cbegin(); it != before.cend(); ++it) {
auto name = it.key();
if (it.value().isLocal() || src.contains(name))
continue;
debug::info("Global unit", name, "is not registered, removing");
if (!rm(name))
error::raise({{"msg", name + " is not removed??"}});
updated = true;
}
return updated;
}
......
......@@ -42,6 +42,7 @@ ENDMACRO(UNIT_IMPL)
UNIT_IMPL(unit1)
UNIT_IMPL(unit2)
install(PROGRAMS unit_fail_vault_test DESTINATION ${TESTS_DIR})
configure_file(tests.xml.in tests.xml @ONLY)
install(FILES tests.xml DESTINATION ${TESTS_DIR})
......
#!/bin/sh
echo "SHOULD FAIL"
echo "FAIL UNIT is FAILED" >&2
exit 1
......@@ -18,6 +18,7 @@
#include <unistd.h>
namespace os = qtaround::os;
namespace subprocess = qtaround::subprocess;
namespace error = qtaround::error;
namespace tut
......@@ -41,7 +42,8 @@ enum test_ids {
tid_config_update,
tid_simple_blobs,
tid_clear,
tid_cli_backup_restore_several_units
tid_cli_backup_restore_several_units,
tid_backup_fail
};
namespace {
......@@ -174,7 +176,7 @@ void object::test<tid_config_update>()
units = vlt->config().units();
ensure("no unit1 in vault config", units.contains("unit1"));
ensure("unit2 should be removed from vault config", !units.contains("unit2"));
ensure("local unit2 should not be removed", units.contains("unit2"));
on_exit();
}
......@@ -298,10 +300,52 @@ void object::test<tid_cli_backup_restore_several_units>()
vault_init();
register_unit(vault_dir, "unit1", false);
register_unit(vault_dir, "unit2", false);
vault::Vault::execute({{"action", "export"}
auto rc = vault::Vault::execute({{"action", "export"}
, {"vault", vault_dir}
, {"home", home}
, {"unit", "unit1,unit2"}});
ensure_eq("Should succeed", rc, 0);
on_exit();
}
template<> template<>
void object::test<tid_backup_fail>()
{
using vault::Vault;
auto on_exit = setup(tid_backup_fail);
auto describe = []() {
subprocess::Process ps;
ps.setWorkingDirectory(vault_dir);
ps.start("git", {"describe", "--tags", "--exact-match"});
return std::move(ps);
};
auto last_snapshot = []() {
return vlt->snapshots().last().name();
};
os::rmtree(home);
os::mkdir(home);
vault_init();
register_unit(vault_dir, "unit1", false);
register_unit(vault_dir, "unit2", false);
auto rc = Vault::execute({{"action", "export"}
, {"vault", vault_dir}
, {"home", home}
, {"unit", "unit1,unit2"}});
ensure_eq("These units should proceed", rc, 0);
auto snap1 = last_snapshot();
register_unit(vault_dir, "unit_fail", false);
rc = Vault::execute({{"action", "export"}
, {"vault", vault_dir}
, {"home", home}
, {"unit", "unit1,unit2,unit_fail"}});
ensure_eq("With failed unit it should fail", rc, 1);
auto ps = describe();
ensure("Git is not found", ps.wait(10));
ensure_eq("There should be a previous tag on top", ps.rc(), 0);
ensure_eq("Should be the same snapshot as before", snap1, last_snapshot());
on_exit();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment