diff --git a/.gitignore b/.gitignore index 40756e0..eb52f55 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,4 @@ units/vault-* *.moc tests/tests.xml tests/*_unit.cpp -tests/*_vault_test src/config.hpp diff --git a/include/vault/config.hpp b/include/vault/config.hpp index 64516d0..42575eb 100644 --- a/include/vault/config.hpp +++ b/include/vault/config.hpp @@ -47,6 +47,7 @@ class Unit 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; }; diff --git a/qml/Vault/vault.cpp b/qml/Vault/vault.cpp index 8d2dc87..00d30d8 100644 --- a/qml/Vault/vault.cpp +++ b/qml/Vault/vault.cpp @@ -64,10 +64,18 @@ class Worker : public QObject 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 diff --git a/src/vault.cpp b/src/vault.cpp index b5fdb82..de6ca44 100644 --- a/src/vault.cpp +++ b/src/vault.cpp @@ -180,8 +180,12 @@ int Vault::execute(const QVariantMap &options) if (!options.contains("data")) { error::raise({{"action", action}, {"msg", "Needs data"}}); } - qDebug()< &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; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ded84e1..237ed8b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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}) diff --git a/tests/unit_fail_vault_test b/tests/unit_fail_vault_test new file mode 100755 index 0000000..9cef0f0 --- /dev/null +++ b/tests/unit_fail_vault_test @@ -0,0 +1,4 @@ +#!/bin/sh +echo "SHOULD FAIL" +echo "FAIL UNIT is FAILED" >&2 +exit 1 diff --git a/tests/vault.cpp b/tests/vault.cpp index 0add0f1..c19994c 100644 --- a/tests/vault.cpp +++ b/tests/vault.cpp @@ -18,6 +18,7 @@ #include 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() 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() 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() +{ + 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(); }