diff --git a/.gitignore b/.gitignore index 0907b9c..1e26774 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ examples/use_cutes src/vault-cli units/vault-* *.moc +tests/tests.xml +tests/*_unit.cpp +tests/*_vault_test \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e4b48cd..37a041b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,22 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gdwarf-3" ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src +) + +pkg_check_modules(QTAROUND qtaround REQUIRED) +pkg_check_modules(COR cor REQUIRED) +include_directories( + ${COR_INCLUDE_DIRS} + ${QTAROUND_INCLUDE_DIRS} +) +link_directories( + ${COR_LIBRARY_DIRS} + ${QTAROUND_LIBRARY_DIRS} +) + add_subdirectory(src) add_subdirectory(examples) add_subdirectory(tests) @@ -49,11 +64,9 @@ add_subdirectory(qml/Vault) configure_file(vault-unit.pc.in vault-unit.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/vault-unit.pc DESTINATION ${DST_LIB}/pkgconfig) -configure_file(qtaround.pc.in qtaround.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qtaround.pc DESTINATION ${DST_LIB}/pkgconfig) install( - DIRECTORY include/vault include/qtaround + DIRECTORY include/vault DESTINATION include FILES_MATCHING PATTERN "*.hpp" diff --git a/examples/test_cutes.cpp b/examples/test_cutes.cpp index 2370f4f..ca12742 100644 --- a/examples/test_cutes.cpp +++ b/examples/test_cutes.cpp @@ -7,6 +7,12 @@ #include #include +namespace os = qtaround::os; +namespace error = qtaround::error; +namespace sys = qtaround::sys; +namespace json = qtaround::json; +namespace debug = qtaround::debug; + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); diff --git a/include/qtaround/debug.hpp b/include/qtaround/debug.hpp deleted file mode 100644 index 91da468..0000000 --- a/include/qtaround/debug.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _CUTES_DEBUG_HPP_ -#define _CUTES_DEBUG_HPP_ -/** - * @file debug.hpp - * @brief Debug tracing support - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include -#include - -#include - -namespace debug { - -enum class Level { Debug = 1, Info, Warning, Error, Critical }; - -QDebug stream(); - -template -QDebug & operator << (QDebug &d, std::function const &) -{ - d << "std::function<...>"; - return d; -} - -static inline void print(QDebug &&d) -{ - QDebug dd(std::move(d)); -} - -template -void print(QDebug &&d, T &&v1, A&& ...args) -{ - d << v1; - return print(std::move(d), std::forward(args)...); -} - -template -void print(A&& ...args) -{ - return print(stream(), std::forward(args)...); -} - -void level(Level); -bool is_tracing_level(Level); - -template -void print_ge(Level print_level, A&& ...args) -{ - if (is_tracing_level(print_level)) - print(std::forward(args)...); -} - -template -void debug(A&& ...args) -{ - print_ge(Level::Debug, std::forward(args)...); -} - -template -void info(A&& ...args) -{ - print_ge(Level::Info, std::forward(args)...); -} - -template -void warning(A&& ...args) -{ - print_ge(Level::Warning, std::forward(args)...); -} - -template -void error(A&& ...args) -{ - print_ge(Level::Error, std::forward(args)...); -} - -template -void critical(A&& ...args) -{ - print_ge(Level::Critical, std::forward(args)...); -} - -} - -#endif // _CUTES_DEBUG_HPP_ diff --git a/include/qtaround/error.hpp b/include/qtaround/error.hpp deleted file mode 100644 index dea4fd6..0000000 --- a/include/qtaround/error.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _CUTES_ERROR_HPP_ -#define _CUTES_ERROR_HPP_ -/** - * @file error.hpp - * @brief Unified exceptions - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include -#include - -namespace error { - -template -QString dump(T && t) -{ - QString s; - QDebug d(&s); - d << t; - return s; -} - -class Error : public std::exception -{ -public: - Error(QVariantMap const &from) : m(from) {} - virtual ~Error() noexcept(true) {} - virtual const char* what() const noexcept(true) - { - if (s.isEmpty()) - s = dump(m); - return s.toUtf8(); - } - - QVariantMap m; - mutable QString s; -}; - -static inline QDebug operator << (QDebug dst, error::Error const &src) -{ - dst << src.m; - return dst; -} - -static inline void raise(QVariantMap const &m) -{ - throw Error(m); -} - -static inline void raise(std::initializer_list > src) -{ - raise(QVariantMap(src)); -} - -template -void raise(T const &m1, T2 const &m2, A && ...args) -{ - QVariantMap x = m1; - QVariantMap y = m2; - x.unite(y); - raise(x, std::forward(args)...); -} - -} - -#endif // _CUTES_ERROR_HPP_ diff --git a/include/qtaround/json.hpp b/include/qtaround/json.hpp deleted file mode 100644 index 9679af9..0000000 --- a/include/qtaround/json.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _CUTES_JSON_HPP_ -#define _CUTES_JSON_HPP_ -/** - * @file json.hpp - * @brief Json access wrappers - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include - -#include -#include -#include - -namespace json { - -QJsonObject read(QString const &); -ssize_t write(QJsonObject const &, QString const &); -ssize_t write(QVariantMap const &, QString const &); - -} - -namespace { - -QVariant get(QJsonValue const &v) -{ - return v.toVariant(); -} - -QVariant get(QJsonObject const &m, QString const &k) -{ - return m[k].toVariant(); -} - -QVariant get(QJsonArray const &a, size_t i) -{ - return a[i].toVariant(); -} - -} - -template -QVariant get(QJsonValue const &v, QString const &k, A&& ...args) -{ - if (!v.isObject()) - return QVariant(); - return get(v.toObject()[k], std::forward(args)...); -} - -template -QVariant get(QJsonValue const &v, size_t i, A&& ...args) -{ - if (!v.isArray()) - return QVariant(); - auto const a = v.toArray(); - return get(a[i], std::forward(args)...); -} - -template -QVariant get(QJsonObject const &m, QString const &k, A&& ...args) -{ - auto v = m[k]; - return get(v, std::forward(args)...); -} - -#endif // _CUTES_JSON_HPP_ diff --git a/include/qtaround/os.hpp b/include/qtaround/os.hpp deleted file mode 100644 index 0083182..0000000 --- a/include/qtaround/os.hpp +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef _CUTES_OS_HPP_ -#define _CUTES_OS_HPP_ -/** - * @file os.hpp - * @brief Wrappers to support API looking familiar for python/shell developers - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include "error.hpp" -#include "sys.hpp" -#include "subprocess.hpp" - -#include -#include -#include -#include -#include - -using subprocess::Process; - -namespace os { -class path -{ -public: - static inline QString join(QString const& a) - { - return a; - } - - template - static QString join(QString const& a, QString const& b, A&& ...args) - { - return join(QStringList({a, b}).join("/"), std::forward(args)...); - } - - static inline bool exists(QString const &p) - { - return QFileInfo(p).exists(); - } - static inline QString canonical(QString const &p) - { - return QFileInfo(p).canonicalFilePath(); - } - static inline QString relative(QString const &p, QString const &d) - { - return QDir(d).relativeFilePath(p); - } - static inline QString deref(QString const &p) - { - return QFileInfo(p).symLinkTarget(); - } - static QString target(QString const &link); - - static inline bool isDir(QString const &p) - { - return QFileInfo(p).isDir(); - } - static inline bool isSymLink(QString const &p) - { - return QFileInfo(p).isSymLink(); - } - static inline bool isFile(QString const &p) - { - return QFileInfo(p).isFile(); - } - static inline QString dirName(QString const &p) - { - return QFileInfo(p).dir().path(); - } - static inline QString fileName(QString const &p) - { - return QFileInfo(p).fileName(); - } - - static QStringList split(QString const &p); - - static bool isDescendent(QString const &p, QString const &other); - -private: - -}; - -int system(QString const &cmd, QStringList const &args = QStringList()); - -bool mkdir(QString const &path, QVariantMap const &options); - -static inline bool mkdir(QString const &path) -{ - return mkdir(path, QVariantMap()); -} - -QByteArray read_file(QString const &fname); -ssize_t write_file(QString const &fname, QByteArray const &data); - -static inline ssize_t write_file(QString const &fname, QString const &data) -{ - return write_file(fname, data.toUtf8()); -} - -static inline ssize_t write_file(QString const &fname, char const *data) -{ - return write_file(fname, QString(data).toUtf8()); -} - -namespace { - -inline QString home() -{ - return QDir::homePath(); -} - -inline int symlink(QString const &tgt, QString const &link) -{ - return system("ln", {"-s", tgt, link}); -} - -inline int rmtree(QString const &path) -{ - return system("rm", {"-rf", path}); -} - -inline int unlink(QString const &what) -{ - return system("unlink", {what}); -} - -inline int rename(QString const &from, QString const &to) -{ - return system("mv", {from, to}); -} - -inline QDateTime lastModified(QString const &path) -{ - return QFileInfo(path).lastModified(); -} - -inline int setLastModified(QString const &path, QDateTime const &timeval) -{ - return system("touch", {"-d", timeval.toString(), path}); -}; - -inline int rm(QString const &path) -{ - return system("rm", {path}); -} - -inline QString environ(QString const &name) -{ - auto c = ::getenv(name.toUtf8()); - return c ? str(c) : QString(); -} - -} - -int cp(QString const &, QString const &, QVariantMap &&); - -static inline int cp(QString const &src, QString const &dst) -{ - return cp(src, dst, QVariantMap()); -} - -int update(QString const &src, QString const &dst - , QVariantMap &&options = QVariantMap()); - -int update_tree(QString const &, QString const &, QVariantMap &&); - -static inline int update_tree(QString const &src, QString const &dst) -{ - return update_tree(src, dst, QVariantMap()); -} - -int cptree(QString const &src, QString const &dst - , QVariantMap &&options = QVariantMap()); - -size_t get_block_size(QString const &); - -QList mount(); -QString mountpoint(QString const &path); -string_map_type stat(QString const &path, QVariantMap &&options = QVariantMap()); -QVariant du(QString const &path, QVariantMap &&options = map({{"summarize", true} - , {"one_filesystem", true}, {"block_size", "K"}})); -double diskFree(QString const &path); -QString mkTemp(QVariantMap &&options = QVariantMap()); - -} - -#endif // _CUTES_OS_HPP_ diff --git a/include/qtaround/subprocess.hpp b/include/qtaround/subprocess.hpp deleted file mode 100644 index 8ce5aa2..0000000 --- a/include/qtaround/subprocess.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef _CUTES_SUBPROCESS_HPP_ -#define _CUTES_SUBPROCESS_HPP_ -/** - * @file subprocess.hpp - * @brief Subprocess execution API resembing std python lib - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include - -#include -#include - -namespace subprocess { - -class Process : public QObject -{ -public: - Process() - : ps(new QProcess()) - , isRunning_(false) - , isError_(false) - {} - - Process(Process &&from) - : ps(std::move(from.ps)) - , isRunning_(from.isRunning_) - , isError_(from.isError_) - {} - - void setWorkingDirectory(QString const &d) - { - ps->setWorkingDirectory(d); - } - - void start(QString const &, QStringList const &); - - bool wait(int timeout); - bool is_error() const; - QString errorInfo() const; - - void popen_sync(QString const &cmd, QStringList const &args) - { - start(cmd, args); - ps->waitForStarted(-1); - } - - int rc() const - { - return is_error() ? -1111 : ps->exitCode(); - } - - qint64 write(QString const &data) - { - return ps->write(data.toUtf8()); - } - - QByteArray stdout() const; - - QByteArray stderr() const; - - void stdinClose() - { - ps->closeWriteChannel(); - } - - Q_PID pid() const - { - return ps->pid(); - } - - void check_error(QVariantMap const &error_info); - void check_error() - { - check_error(QVariantMap()); - } - - QByteArray check_output(QString const &, QStringList const &, QVariantMap const &); - QByteArray check_output(QString const &cmd, QStringList const &args) - { - return check_output(cmd, args, QVariantMap()); - } - - int check_call(QString const &, QStringList const &, QVariantMap const &); - int check_call(QString const &cmd, QStringList const &args) - { - return check_call(cmd, args, QVariantMap()); - } - -private: - - mutable std::unique_ptr ps; - bool isRunning_; - bool isError_; - -private slots: - void onError(QProcess::ProcessError); - void onFinished(int, QProcess::ExitStatus); -}; - -QByteArray check_output(QString const &cmd, QStringList const &args, QVariantMap const &); -static inline QByteArray check_output(QString const &cmd, QStringList const &args) -{ - return check_output(cmd, args, QVariantMap()); -} - -int check_call(QString const &cmd, QStringList const &args, QVariantMap const &); -static inline int check_call(QString const &cmd, QStringList const &args) -{ - return check_call(cmd, args, QVariantMap()); -} - - -} -#endif // _CUTES_SUBPROCESS_HPP_ diff --git a/include/qtaround/sys.hpp b/include/qtaround/sys.hpp deleted file mode 100644 index 57e80d8..0000000 --- a/include/qtaround/sys.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _CUTES_SYS_HPP_ -#define _CUTES_SYS_HPP_ -/** - * @file sys.hpp - * @brief Command line parsing and generation etc. - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include - -#include - -namespace sys { - -QStringList command_line_options -(QVariantMap const &options - , string_map_type const &short_options = string_map_type() - , string_map_type const &long_options = string_map_type() - , QSet const &options_has_param = QSet()); - -class GetOpt -{ -public: - virtual ~GetOpt() {} - virtual QString value(QString const &name) const =0; - virtual bool isSet(QString const &name) const =0; - virtual QStringList arguments() const =0; -}; - -std::unique_ptr getopt(QVariantMap const &, bool requireAll = true); - -} - -#endif // _CUTES_SYS_HPP_ diff --git a/include/qtaround/util.hpp b/include/qtaround/util.hpp deleted file mode 100644 index 8d926f4..0000000 --- a/include/qtaround/util.hpp +++ /dev/null @@ -1,314 +0,0 @@ -#ifndef _CUTES_UTIL_HPP_ -#define _CUTES_UTIL_HPP_ -/** - * @file util.hpp - * @brief Misc. helpful utilities - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include "error.hpp" - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace { - -inline QString str(QVariant const &v) -{ - return v.toString(); -} - -inline QString str(QByteArray const &v) -{ - return QString::fromUtf8(v); -} - -inline QString str(int v) -{ - return QString::number(v); -} - -inline QString str(char const *v) -{ - return QString(v); -} - -inline bool is(QVariant const &v) -{ - return v.toBool(); -} - -inline bool is(QString const &v) -{ - return v.isEmpty() ? false : v.toUInt(); -} - -inline bool hasType(QVariant const &v, QMetaType::Type t) -{ - return static_cast(v.type()) == t; -} - -template X get(Y const &); - -template <> -double get(QVariant const &v) -{ - return v.toDouble(); -} - -typedef QVariantMap map_type; -typedef QMap string_map_type; -typedef QList list_type; -typedef std::tuple map_tuple_type; - -inline QVariantMap map(std::initializer_list > data) -{ - return QVariantMap(data); -} - -inline QVariantList list(std::initializer_list data) -{ - return QVariantList(data); -} - -inline QVariantMap map(QVariant const &v, bool check_type = true) -{ - if (check_type && !hasType(v, QMetaType::QVariantMap)) - error::raise({{"msg", "Need QVariantMap"}, {"value", v}}); - return v.toMap(); -} - -inline QVariantMap const & map(QVariantMap const &data) -{ - return data; -} - -template -inline QMap map(QList > const &src) -{ - QMap res; - for (auto it = src.begin(); it != src.end(); ++it) { - res.insert(std::get<0>(*it), std::get<1>(*it)); - } - return res; -} - -QVariant get(QVariantMap const &m, QString const &k1) -{ - return m[k1]; -} - -inline QStringList filterEmpty(QStringList const &src) -{ - return src.filter(QRegExp("^.+$")); -} - -template<> -QString get(QVariant const &from) -{ - return from.toString(); -} - -} - -template -QVariant get(QVariantMap const &m, QString const &k1, QString const &k2, A&& ...args) -{ - auto const &v = m[k1]; - return get(v.toMap(), k2, std::forward(args)...); -} - -template -std::unique_ptr box(T &&v) -{ - std::unique_ptr p(new T(std::move(v))); - return p; -} - -template -T unbox(std::unique_ptr p) -{ - return std::move(*p); -} - -template struct StructTraits; - -template -struct Struct -{ - typedef FieldsT id_type; - typedef typename StructTraits::type data_type; - static_assert(static_cast(FieldsT::EOE) == std::tuple_size::value - , "Enum should end with EOE == tuple size"); - - Struct(data_type const &src) : data(src) {} - Struct(data_type &&src) : data(std::move(src)) {} - - template - Struct(Args &&...args) : data(std::forward(args)...) {} - - template - typename std::tuple_element(Id), data_type>::type &get() - { - return std::get::value>(data); - } - - template - typename std::tuple_element(Id), data_type>::type const & - get() const - { - return std::get::value>(data); - } - - template - struct Index { - static_assert(Id != FieldsT::EOE, "Should not be EOE"); - static const size_t value = static_cast(Id); - }; - - template - struct Enum { - static const FieldsT value = static_cast(Index); - static_assert(value < FieldsT::EOE, "Should be < EOE"); - }; - -private: - data_type data; -}; - -template -constexpr size_t count(Args &&...) -{ - return sizeof...(Args); -} - -#define STRUCT_NAMES(Id, id_names...) \ - template \ - static char const * name() \ - { \ - auto const end = static_cast(Id::EOE); \ - static const std::array names{{id_names}}; \ - static_assert(count(id_names) == end, "Check names count"); \ - return names[Struct::Index::value]; \ - } - -namespace debug { - -template -struct StructDump -{ - template - static void out(QDebug &d, Struct const &v) - { - static auto const end = (size_t)FieldsT::EOE; - static auto const id = Struct::template Enum::value; - static auto const *name(StructTraits::template name()); - auto const &r = v.template get(); - d << name << "=" << r << ", "; - StructDump::out(d, v); - } -}; - -template <> -struct StructDump<1> -{ - template - static void out(QDebug &d, Struct const &v) - { - static auto const end = (size_t)FieldsT::EOE; - static auto const id = Struct::template Enum::value; - static auto const *name(StructTraits::template name()); - auto const &r = v.template get(); - d << name << "=" << r; - } -}; - -template -QDebug & operator <<(QDebug &d, Struct const &v) -{ - static const auto index = (size_t)FieldsT::EOE; - static_assert(index != 0, "Struct should"); - d << "("; StructDump::out(d, v); d << ")"; - return d; -} - -} - -namespace util { - -template -QList map(FnT fn, QList const &src) -{ - QList res; - for (auto it = src.begin(); it != src.end(); ++it) { - res.push_back(fn(*it)); - } - return res; -} - -template -QList map(FnT fn, QMap const &src) -{ - QList res; - for (auto it = src.begin(); it != src.end(); ++it) { - res.push_back(fn(it.key(), it.value())); - } - return res; -} - -template -QList map(FnT fn, QString const &src) -{ - QList res; - for (auto it = src.begin(); it != src.end(); ++it) { - res.push_back(fn(*it)); - } - return res; -} - -template -QList > zip(QList const &x, QList const &y) -{ - QList > res; - auto yit = y.begin(); - auto xit = x.begin(); - for(;xit != x.end(); ++xit, ++yit) { - if (yit != y.end()) - res.push_back(std::make_tuple(*xit, *yit)); - else - break; - } - for(;xit != x.end(); ++xit) - res.push_back(std::make_tuple(*xit, Y())); - - return res; -} - -template -QMap mapByField(QList const &src, K const &key) -{ - auto fn = [&key](T const &v) { return std::make_tuple(get(v[key]), v); }; - auto pairs = map >(fn, src); - return ::map(pairs); -} - -double parseBytes(QString const &s, QString const &unit = "b" - , long multiplier = 1024); - -typedef std::function visitor_type; -QVariant visit(visitor_type visitor, QVariant const &src, QVariant const &ctx); - -} - -#endif // _CUTES_UTIL_HPP_ diff --git a/include/vault/config.hpp b/include/vault/config.hpp index a78c7d2..64516d0 100644 --- a/include/vault/config.hpp +++ b/include/vault/config.hpp @@ -22,6 +22,8 @@ namespace vault { namespace config { namespace { +namespace os = qtaround::os; + const QString prefix = ".f8b52b7481393a3e6ade051ecfb549fa"; static inline QString units_path(QString const &vaultDir) diff --git a/include/vault/unit.hpp b/include/vault/unit.hpp index 91546b5..fede10e 100644 --- a/include/vault/unit.hpp +++ b/include/vault/unit.hpp @@ -11,13 +11,14 @@ #include #include -namespace sys { class GetOpt; } +namespace qtaround { namespace sys { class GetOpt; }} namespace vault { namespace unit { -std::unique_ptr getopt(); +typedef std::unique_ptr options_uptr; +options_uptr getopt(); -int execute(std::unique_ptr, QVariantMap const &info); +int execute(options_uptr, QVariantMap const &info); }} diff --git a/qml/Vault/vault.cpp b/qml/Vault/vault.cpp index 2e5414c..1c9c233 100644 --- a/qml/Vault/vault.cpp +++ b/qml/Vault/vault.cpp @@ -8,6 +8,10 @@ #include "vault.hpp" +namespace os = qtaround::os; +namespace error = qtaround::error; +namespace debug = qtaround::debug; + Q_DECLARE_METATYPE(Vault::Operation) static const int _vault_operation_ __attribute__((unused)) = qRegisterMetaType(); diff --git a/qtaround.pc.in b/qtaround.pc.in deleted file mode 100644 index 20277e6..0000000 --- a/qtaround.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -libdir=${prefix}/@DST_LIB@ -includedir=${prefix}/include - -Name: cutespp -Description: cutespp library -Version: @VERSION@ -Libs: -lqtaround -L${libdir} -Cflags: -I${includedir} \ No newline at end of file diff --git a/rpm/vault.spec b/rpm/vault.spec index 7de57f7..2a9649e 100644 --- a/rpm/vault.spec +++ b/rpm/vault.spec @@ -12,6 +12,7 @@ BuildRequires: pkgconfig(gittin) BuildRequires: pkgconfig(tut) >= 0.0.3 BuildRequires: pkgconfig(Qt5Core) >= 5.2.0 BuildRequires: pkgconfig(Qt5Qml) +BuildRequires: pkgconfig(qtaround) >= 0.2.0 Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig @@ -25,20 +26,13 @@ Requires: %{name} = %{version}-%{release} %description devel vault library header files etc. -%package -n qtaround -Summary: QtAround library -Group: Development/Libraries -%description -n qtaround -QtAround library used to port the-vault to C++. Mostly consists of -thin wrappers around Qt classes and standard Linux utilities. - -%package -n qtaround-devel -Summary: QtAround library -Group: Development/Libraries -Requires: qtaround = %{version}-%{release} -%description -n qtaround-devel -QtAround library used to port the-vault to C++. Mostly consists of -thin wrappers around Qt classes and standard Linux utilities. +%package tests +Summary: Tests for vault +License: LGPLv2.1 +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} +%description tests +%summary %prep %setup -q @@ -68,18 +62,9 @@ rm -rf $RPM_BUILD_ROOT %dir %{_includedir}/vault %{_includedir}/vault/*.hpp -%files -n qtaround +%files tests %defattr(-,root,root,-) -%{_libdir}/libqtaround.so* - -%files -n qtaround-devel -%defattr(-,root,root,-) -%{_libdir}/pkgconfig/qtaround.pc -%dir %{_includedir}/qtaround -%{_includedir}/qtaround/*.hpp +/opt/tests/vault/* %post -p /sbin/ldconfig %postun -p /sbin/ldconfig - -%post -n qtaround -p /sbin/ldconfig -%postun -n qtaround -p /sbin/ldconfig diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 38e2e08..d84ba57 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,27 +1,20 @@ -pkg_check_modules(COR cor REQUIRED) pkg_check_modules(GITTIN gittin REQUIRED) include_directories( - ${COR_INCLUDE_DIRS} ${GITTIN_INCLUDE_DIRS} + ${GITTIN_INCLUDE_DIRS} ) link_directories( - ${COR_LIBRARY_DIRS} ${GITTIN_LIBRARY_DIRS} + ${GITTIN_LIBRARY_DIRS} ) set(CMAKE_AUTOMOC TRUE) -add_library(qtaround SHARED debug.cpp os.cpp json.cpp sys.cpp subprocess.cpp util.cpp) -qt5_use_modules(qtaround Core) -target_link_libraries(qtaround ${COR_LIBRARIES}) -set_target_properties(qtaround PROPERTIES - SOVERSION 0 - VERSION ${VERSION} - ) -install(TARGETS qtaround DESTINATION ${DST_LIB}) - add_library(vault-core SHARED vault.cpp vault_config.cpp) qt5_use_modules(vault-core Core) -target_link_libraries(vault-core qtaround ${GITTIN_LIBRARIES}) +target_link_libraries(vault-core + ${QTAROUND_LIBRARIES} + ${GITTIN_LIBRARIES} +) set_target_properties(vault-core PROPERTIES SOVERSION 0 VERSION ${VERSION} @@ -35,7 +28,10 @@ install(TARGETS vault-cli DESTINATION bin) add_library(vault-unit SHARED unit.cpp) qt5_use_modules(vault-unit Core) -target_link_libraries(vault-unit ${COR_LIBRARIES} qtaround) +target_link_libraries(vault-unit + ${COR_LIBRARIES} + ${QTAROUND_LIBRARIES} +) set_target_properties(vault-unit PROPERTIES SOVERSION 0 VERSION ${VERSION} @@ -44,7 +40,11 @@ install(TARGETS vault-unit DESTINATION ${DST_LIB}) add_library(vault-transfer SHARED transfer.cpp) qt5_use_modules(vault-transfer Core) -target_link_libraries(vault-transfer ${COR_LIBRARIES} qtaround vault-core) +target_link_libraries(vault-transfer + ${COR_LIBRARIES} + ${QTAROUND_LIBRARIES} + vault-core +) set_target_properties(vault-transfer PROPERTIES SOVERSION 0 VERSION ${VERSION} diff --git a/src/debug.cpp b/src/debug.cpp deleted file mode 100644 index 6cc13e4..0000000 --- a/src/debug.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file debug.cpp - * @brief Debug tracing support - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include -#include -#include - -namespace debug { - -namespace { - -int current_level = static_cast(Level::Error); -std::mutex mutex; -bool is_init = false; - -void init() -{ - if (!is_init) { - std::lock_guard l(mutex); - if (is_init) - return; - auto c = ::getenv("CUTES_DEBUG"); - if (c) { - std::string name(c); - current_level = name.size() ? std::stoi(name) : (int)Level::Critical; - } - is_init = true; - } -} - -} - -QDebug stream() -{ - init(); - return qDebug(); -} - -void level(Level level) -{ - init(); - current_level = static_cast(level); -} - -bool is_tracing_level(Level level) -{ - init(); - auto l = static_cast(level); - return current_level ? l >= current_level : false; -} - -} diff --git a/src/json.cpp b/src/json.cpp deleted file mode 100644 index dd3e4f4..0000000 --- a/src/json.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file json.cpp - * @brief Json access wrappers - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include - -#include -#include -#include -#include - -namespace json { - -QJsonObject read(QString const &fname) -{ - auto data = os::read_file(fname); - auto doc = QJsonDocument::fromJson(data); - return doc.object(); -} - -ssize_t write(QJsonObject const &src, QString const &fname) -{ - QJsonDocument doc(src); - return os::write_file(fname, doc.toJson()); -} - -ssize_t write(QVariantMap const &src, QString const &fname) -{ - return write(QJsonObject::fromVariantMap(src), fname); -} - -} diff --git a/src/os.cpp b/src/os.cpp deleted file mode 100644 index b44d624..0000000 --- a/src/os.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/** - * @file os.cpp - * @brief Wrappers to support API looking familiar for python/shell developers - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include -#include - -namespace os { - -QStringList path::split(QString const &p) -{ - auto parts = p.split('/'); - auto len = parts.size(); - - if (len <= 1) - return parts; - - if (parts[0] == "") - parts[0] = '/'; - - auto end = std::remove_if - (parts.begin(), parts.end(), [](QString const &v) { - return v == "";}); - parts.erase(end, parts.end()); - return parts; -} - -bool path::isDescendent(QString const &p, QString const &other) { - auto tested = split(canonical(p)); - auto pivot = split(canonical(other)); - - // hardlinks? - if (pivot.size() > tested.size()) - return false; - for (int i = 0; i < pivot.size(); ++i) { - if (pivot[i] != tested[i]) - return false; - } - return true; -} - -QString path::target(QString const &link) -{ - // TODO use c lstat+readlink - return str(subprocess::check_output("readlink", {link})).split('\n')[0]; -} - -int system(QString const &cmd, QStringList const &args) -{ - Process p; - p.start(cmd, args); - p.wait(-1); - return p.rc(); -} - -bool mkdir(QString const &path, QVariantMap const &options) -{ - QVariantMap err = {{"fn", "mkdir"}, {"path", path}}; - if (path::isDir(path)) - return false; - if (options.value("parent", false).toBool()) - return system("mkdir", {"-p", path}) == 0; - return system("mkdir", {path}) == 0; -} - -int update (QString const &src, QString const &dst, QVariantMap &&options) -{ - options["update"] = true; - return cp(src, dst, std::move(options)); -} - -int update_tree(QString const &src, QString const &dst, QVariantMap &&options) -{ - options["deref"] = true; - options["recursive"] = true; - return update(src, dst, std::move(options)); -} - -int cp(QString const &src, QString const &dst, QVariantMap &&options) -{ - string_map_type short_options = { - {"recursive", "r"}, {"force", "f"}, {"update", "u"} - , {"deref", "L"}, {"no_deref", "P"}, - {"hardlink", "l"} - }; - string_map_type long_options = { - {"preserve", "preserve"}, {"no_preserve", "no-preserve"} - , {"overwrite", "remove-destination"} - }; - - auto args = sys::command_line_options - (options, short_options, long_options - , {{"preserve", "no_preserve"}}); - - args += QStringList({src, dst}); - return system("cp", args); -} - -int cptree(QString const &src, QString const &dst, QVariantMap &&options) -{ - options["recursive"] = true; - options["force"] = true; - return cp(src, dst, std::move(options)); -} - -QByteArray read_file(QString const &fname) -{ - QFile f(fname); - if (!f.open(QFile::ReadOnly)) - return QByteArray(); - return f.readAll(); -} - -ssize_t write_file(QString const &fname, QByteArray const &data) -{ - QFile f(fname); - if (!f.open(QFile::WriteOnly)) - return 0; - - return f.write(data); -} - -size_t get_block_size(QString const &cmd_name) -{ - size_t res = 0; - const QMap prefices = {{"df", "DF"}, {"du", "DU"}}; - auto prefix = prefices[cmd_name]; - auto names = !prefix.isEmpty() ? QStringList(QStringList({prefix, "BLOCK_SIZE"}).join("_")) : QStringList(); - names += QStringList({"BLOCK_SIZE", "BLOCKSIZE"}); - for (auto it = names.begin(); it != names.end(); ++it) { - auto const &name = *it; - auto v = environ(name); - if (!v.isEmpty()) { - bool ok = false; - res = v.toUInt(&ok); - if (ok) - break; - } - } - return (res ? res : (is(environ("POSIXLY_CORRECT")) ? 512 : 1024)); -} - -QList mount() -{ - auto line2obj = [](QString const &line) { - static const QStringList names = {"src", "dst", "type", "options"}; - auto fields = line.split(QRegExp("\\s+")); - return map(util::zip(names, fields)); - }; - auto split_options = [](QMap const &fields) { - QVariantMap res; - for (auto it = fields.begin(); it != fields.end(); ++it) { - if (it.key() != "options") - res.insert(it.key(), it.value()); - else - res.insert(it.key(), it.value().split(",")); - } - return res; - }; - - auto data = str(subprocess::check_output("cat", {"/proc/mounts"})); - auto lines = filterEmpty(data.split("\n")); - auto fields = util::map >(line2obj, lines); - return util::map(split_options, fields); -} - -QString mountpoint(QString const &path) -{ - QStringList commands = {"df -P " + path, "tail -1", "awk '{ print $NF; }'"}; - QStringList options = {"-c", commands.join(" | ")}; - auto data = subprocess::check_output("sh", options); - auto res = str(data).split("\n")[0]; - debug::info("Mountpoint for", path, "=", path); - return res; -} - -/** - * options.fields - sequence of characters used for field ids used by - * stat (man 1 stat) - */ -string_map_type stat(QString const &path, QVariantMap &&options) -{ - debug::debug("stat", path, options); - - static const string_map_type long_options = { - {"filesystem", "file-system"}, {"format", "format"}}; - - if (!hasType(options["fields"], QMetaType::QString)) - error::raise({{"msg", "Need to have fields set in options"}}); - - auto const &requested = str(options["fields"]); - - auto commify = [](QString const &fields) { - auto prepend = [](QChar const &c) { return QString("%") + c; }; - return QStringList(util::map(prepend, fields)).join(","); - }; - options["format"] = commify(requested); - - auto cmd_options = sys::command_line_options(options, {}, long_options, {"format"}); - cmd_options.push_back(path); - - auto data = str(subprocess::check_output("stat", cmd_options)).trimmed().split(","); - if (data.size() != requested.size()) - error::raise({{"msg", "Fields set length != stat result length"} - , {"fields", options["fields"]} - , {"format", options["format"]} - , {"result", data}}); - - static const string_map_type filesystem_fields = { - {"b", "blocks"}, {"a", "free_blocks_user"}, {"f", "free_blocks"} - , {"S", "block_size"}, {"n", "name"}}; - static const string_map_type entry_fields = { - {"m", "mount_point"}, {"b", "blocks"}, {"B", "block_size"}, {"s", "size"}}; - - - string_map_type res; - int i = 0; - auto const &fields = is(options["filesystem"]) ? filesystem_fields : entry_fields; - for (auto it = data.begin(); it != data.end(); ++it) { - auto value = *it; - auto c = requested[i++]; - auto name = fields[c]; - if (name.isEmpty()) - error::raise({{"msg", "Can't find field name"}, {"id", c}}); - if (c == 'm' && value == "?") { - // workaround if "m" is not supported - value = mountpoint(path); - } - res[name] = value; - } - debug::debug("stat result", path, res); - return res; -} - -class BtrFs { -public: - - BtrFs(QString const &mount_point) : path(mount_point) {} - - QVariantMap df() - { - QStringList cmd_options = {"-c", "btrfs fi df " + path}; - auto out = str(subprocess::check_output("sh", cmd_options)); - auto data = filterEmpty(out.trimmed().split("\n")); - - auto split_colon = [](QString const &l) { return l.split(":"); }; - auto name_fields = util::map(split_colon, data); - - auto parse = [](QStringList const &nf) { - auto parse_size = [](QString const &n_eq_v) { - auto nv = n_eq_v.trimmed().split("="); - auto kb = util::parseBytes(nv[1], "kb", kb_bytes); - return std::make_tuple(nv[0], kb); - }; - auto names_kbs = util::map(parse_size, nf[1].split(",")); - auto fields = map(names_kbs); - return std::make_tuple(nf[0], QVariant(fields)); - }; - return map(util::map(parse, name_fields)); - } - - double free() - { - debug::debug("btrfs.free for", path); - auto s = stat(path, {{"fields", "bS"}, {"filesystem", true}}); - auto b = s["blocks"].toLong(), bs = s["block_size"].toLong(); - auto kb = bs / kb_bytes; - auto total = kb * b; - auto info = df(); - - auto used = util::map([](QString const &, QVariant const &v) { - auto get_used = [](QString const &k, QVariant const &v) { - return (k == "used") ? v.toDouble() : 0.0; - }; - auto used = util::map(get_used, v.toMap()); - return std::accumulate(used.begin(), used.end(), 0.0); - }, info); - return total - std::accumulate(used.begin(), used.end(), 0.0); - } - -private: - static const size_t kb_bytes = 1024; - QString path; -}; - -double diskFree(QString const &path) -{ - debug::debug("diskFree for", path); - auto s = stat(path, {{"fields", "m"}}); - auto mount_point = s["mount_point"]; - if (mount_point == "?") - mount_point = mountpoint(path); - auto mounts = util::mapByField(mount(), "dst"); - auto info = mounts[mount_point]; - if (info.empty()) - error::raise({{"msg", "Can't find mount point"} - , {"path", path} - , {"mounts", QVariant::fromValue(mounts)}}); - double res = 0.0; - if (str(info["type"]) == "btrfs") { - res = BtrFs(mount_point).free(); - } else { - s = stat(mount_point, {{"fields", "aS"}, {"filesystem", true}}); - auto b = s["free_blocks_user"].toDouble(), bs = s["block_size"].toDouble(); - auto kb = bs / 1024; - res = kb * b; - } - debug::debug("diskFree for", path, "=", res); - return res; -} - -QVariant du(QString const &path, QVariantMap &&options) -{ - static const string_map_type short_options = { - {"summarize", "s"}, {"one_filesystem", "x"}, {"block_size", "B"} }; - - if (!options["block_size"].isValid()) // return usage in K - options["block_size"] = "K"; - - auto cmd_options = sys::command_line_options - (options, short_options, {}, {"block_size"}); - cmd_options.push_back(path); - - auto out = str(subprocess::check_output("du", cmd_options)); - auto data = filterEmpty(out.split("\n")); - auto extract_size = [](QString const &line) { - auto s = line.trimmed(); - auto pos = s.indexOf(QRegExp("\\s")); - if (pos < 0) - pos = s.size(); - return util::parseBytes(s.left(pos), "K"); - }; - if (data.size() == 1) - return extract_size(data[0]); - - static const QRegExp spaces_re("\\s"); - auto fields = util::map([](QString const &v) { - return v.split(spaces_re); - }, data); - auto get_sizes = [&extract_size](QStringList const &v) { - return std::make_tuple(v[1], extract_size(v[0])); - }; - auto pairs = util::map(get_sizes, fields); - return map(pairs); -} - -QString mkTemp(QVariantMap &&options) -{ - if (options.empty()) - options["dir"] = false; - - string_map_type short_options = {{"dir", "d"}}; - auto args = sys::command_line_options(options, short_options); - auto res = str(subprocess::check_output("mktemp", args)); - return res.trimmed(); -} - -} // os diff --git a/src/subprocess.cpp b/src/subprocess.cpp deleted file mode 100644 index 34d481d..0000000 --- a/src/subprocess.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @file subprocess.cpp - * @brief Subprocess execution API resembing std python lib - * @author Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include -#include -#include -#include - -namespace subprocess { - -void Process::start(QString const &cmd, QStringList const &args) -{ - if (isRunning_) - error::raise({{"msg", "Can't start process, it is running"} - , {"cmd", cmd}, {"args", QVariant(args)}}); - debug::info("Start", cmd, args); - connect(ps.get(), static_cast - (&QProcess::finished), this, &Process::onFinished); - connect(ps.get(), static_cast - (&QProcess::error), this, &Process::onError); - isError_ = false; - ps->start(cmd, args); -} - -namespace { - -const QMap errorNames = { - {QProcess::FailedToStart, "FailedToStart"} - , {QProcess::Crashed, "Crashed"} - , {QProcess::Timedout, "Timedout"} - , {QProcess::WriteError, "WriteError"} - , {QProcess::ReadError, "ReadError"} - , {QProcess::UnknownError, "UnknownError"} -}; - -} // namespace - -QString Process::errorInfo() const -{ - if (isRunning_ || !rc()) - return QString(); - QString res; - QDebug(&res) << errorNames[ps->error()] << ps->exitStatus(); - return res; -} - -void Process::onError(QProcess::ProcessError err) -{ - debug::warning("Process returned error", errorNames[err]); - isRunning_ = false; - isError_ = true; -} - -void Process::onFinished(int res, QProcess::ExitStatus status) -{ - debug::info("Process is finished", res, status); - isRunning_ = false; - isError_ = false; -} - -bool Process::wait(int timeout) -{ - auto res = (ps->state() == QProcess::NotRunning) - || ps->waitForFinished(timeout) - || (ps->state() == QProcess::NotRunning); - isRunning_ = !res; - return res; -} - -bool Process::is_error() const -{ - if (isError_) - return true; - - auto e = ps->error(); - auto status = ps->exitStatus(); - return (status == QProcess::NormalExit - && (e == QProcess::UnknownError - || (!isRunning_ && e == QProcess::Timedout)) - ? false - : true); -} - -void Process::check_error(QVariantMap const &error_info) -{ - if (!rc()) - return; - QVariantMap err = {{"msg", "Process error"} - , {"cmd", ps->program()} - , {"args", QVariant(ps->arguments())} - , {"rc", rc()} - , {"stderr", stderr()} - , {"stdout", stdout()} - , {"info", errorInfo()}}; - err.unite(error_info); - error::raise(err); -} - -QByteArray Process::check_output -(QString const &cmd, QStringList const &args, QVariantMap const &error_info) -{ - start(cmd, args); - wait(-1); - check_error(error_info); - return stdout(); -} - -int Process::check_call -(QString const &cmd, QStringList const &args, QVariantMap const &error_info) -{ - start(cmd, args); - wait(-1); - check_error(error_info); - return rc(); -} - -QByteArray Process::stdout() const -{ - auto res = ps->readAllStandardOutput(); - debug::debug("Stdout", res); - return res; -} - -QByteArray Process::stderr() const -{ - auto res = ps->readAllStandardError(); - debug::debug("Stderr", res); - return res; -} - - -QByteArray check_output(QString const &cmd, QStringList const &args - , QVariantMap const &error_info) -{ - Process p; - return p.check_output(cmd, args, error_info); -} - -int check_call(QString const &cmd, QStringList const &args - , QVariantMap const &error_info) -{ - Process p; - return p.check_call(cmd, args, error_info); -} - -} diff --git a/src/sys.cpp b/src/sys.cpp deleted file mode 100644 index edfedcf..0000000 --- a/src/sys.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @file sys.cpp - * @brief Command line parsing and generation etc. - * @author Giulio Camuffo , Denis Zalevskiy - * @copyright (C) 2014 Jolla Ltd. - * @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - */ - -#include - -#include - -#include -#include - -namespace sys { -QStringList command_line_options(QVariantMap const &options - , string_map_type const &short_options - , string_map_type const &long_options - , QSet const &options_has_param) -{ - QStringList cmd_options; - - for (auto it = options.begin(); it != options.end(); ++it) { - auto n = it.key(); - auto v = it.value(); - auto opt = short_options[n]; - if (!opt.isEmpty()) { - if (options_has_param.contains(n)) { - auto params = QStringList({QString("-")+ opt, str(v)}); - cmd_options.append(params); - } else { - if (v.toBool()) - cmd_options.push_back(QString("-") + opt); - } - continue; - } - opt = long_options[n]; - if (!opt.isEmpty()) { - if (options_has_param.contains(n)) { - auto long_opt = QStringList({"--", opt, "=", str(v)}).join(""); - cmd_options.push_back(long_opt); - } else { - if (v.toBool()) - cmd_options.push_back(QString("--") + opt); - } - } - }; - return cmd_options; -} - -class OptionsImpl : public GetOpt -{ -public: - OptionsImpl() - {} - - void addOption(const QString &shortName, const QString &longName, - const QString &description, const QString &defaultValue) - { - QStringList names = { QString("-") + shortName, QString("--") + longName }; - auto opt = std::make_shared(args)...); } +} + +#define S_(...) strings(__VA_ARGS__).join(' ').toStdString() + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) + #endif // _VAULT_TESTS_COMMON_HPP_ diff --git a/tests/transfer.cpp b/tests/transfer.cpp index d48f0db..2c87caf 100644 --- a/tests/transfer.cpp +++ b/tests/transfer.cpp @@ -22,6 +22,8 @@ #include #include +namespace subprocess = qtaround::subprocess; + namespace tut { @@ -47,15 +49,6 @@ namespace { using vault::Vault; std::unique_ptr the_vault; -void register_unit(QString const &vault_dir, QString const &name) -{ - QVariantMap data = {{"action", "register"}, - {"data", "name=" + name + ",group=group1," - + "script=./" + name}, - {"vault", vault_dir}}; - return vault::Vault::execute(data); -}; - void init_vault(QString const &vault_dir) { tut::ensure("Vault dir is path", !vault_dir.isEmpty()); @@ -70,7 +63,7 @@ void create_backup() auto vault_dir = str(get(context, "vault_dir")); init_vault(vault_dir); mktree(unit1_tree, str(get(context, "unit1_dir"))); - register_unit(vault_dir, "unit1"); + register_unit(vault_dir, "unit1", false); bool is_started = false, is_failed = false; the_vault->backup(home, {}, "", [&](const QString &, const QString &status) { @@ -115,19 +108,6 @@ void object::test() create_backup(); } -void ensure_trees_equal(QString const &msg - , QSet const &before - , QSet const &after) -{ - auto before_wo_after = before - after; - auto after_wo_before = after - before; - // compare to see difference on failure - ensure_eq(msg + ": something is appeared" - , after_wo_before, QSet()); - ensure_eq(msg + ": something was removed" - , before_wo_after, QSet()); -} - template<> template<> void object::test() { diff --git a/tests/unit.cpp b/tests/unit.cpp index 63f1096..d7fb2f1 100644 --- a/tests/unit.cpp +++ b/tests/unit.cpp @@ -13,6 +13,11 @@ #include #include +namespace os = qtaround::os; +namespace subprocess = qtaround::subprocess; +namespace error = qtaround::error; +namespace sys = qtaround::sys; + namespace tut { @@ -77,7 +82,7 @@ void setup() auto root_path = it.value(); mkdir(root_path); - using os::path; + namespace path = os::path; auto dir_content = path::join(root_path, "content"); mkdir(dir_content); mkdir(path::join(dir_content, "content_subdir")); diff --git a/tests/unit1_vault_test.cpp b/tests/unit1_vault_test.cpp index 105f8c0..4644a8a 100644 --- a/tests/unit1_vault_test.cpp +++ b/tests/unit1_vault_test.cpp @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); using namespace vault::unit; execute(getopt(), info); - } catch (error::Error const &e) { + } catch (qtaround::error::Error const &e) { qDebug() << e; } catch (std::exception const &e) { qDebug() << e.what(); diff --git a/tests/unit_all.cpp b/tests/unit_all.cpp index fed95ff..964a3fe 100644 --- a/tests/unit_all.cpp +++ b/tests/unit_all.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); using namespace vault::unit; execute(getopt(), info); - } catch (error::Error const &e) { + } catch (qtaround::error::Error const &e) { qDebug() << e; } catch (std::exception const &e) { qDebug() << e.what(); diff --git a/tests/vault.cpp b/tests/vault.cpp index d99c497..0add0f1 100644 --- a/tests/vault.cpp +++ b/tests/vault.cpp @@ -1,3 +1,5 @@ +#include "vault_context.hpp" + #include #include #include @@ -5,7 +7,6 @@ #include #include -#include "tests_common.hpp" #include //#include "tests_common.hpp" @@ -16,6 +17,9 @@ #include #include +namespace os = qtaround::os; +namespace error = qtaround::error; + namespace tut { @@ -54,17 +58,24 @@ const QSet options_has_param = { {"bin-dir", "dir", "home-dir", "action"} }; -const QString home = "/tmp/.test-the-vault-431f7f8b665d3cc2a1a4a8c3c74ad5ff"; -const QString vault_dir = os::path::join(home, ".vault"); -const QString global_mod_dir = os::path::join(home, ".units"); -vault::Vault vlt(vault_dir); +// separate home for each test +QString home; +QString vault_dir = os::path::join(home, ".vault"); +QString global_mod_dir = os::path::join(home, ".units"); +std::unique_ptr vlt; -std::function setup() +std::function setup(test_ids id) { - if (os::path::exists(home)) { - error::raise({{"dir", home}, {"msg", "should not exist"}}); - } - os::mkdir(home); + reinitContext(QString::number(id)); + home = str(context["home"]); + if (os::path::exists(home)) + error::raise({{"dir", home}, {"msg", "Shouldn't exists"}}); + + if (!os::mkdir(home)) + error::raise({{"dir", home}, {"msg", "Can't create"}}); + vault_dir = os::path::join(home, ".vault"); + global_mod_dir = os::path::join(home, ".units"); + vlt.reset(new vault::Vault(vault_dir)); vault::config::global()->setUnitsDir(global_mod_dir); os::rmtree(global_mod_dir); @@ -78,29 +89,16 @@ std::function setup() void vault_init() { QVariantMap git_cfg = {{"user.name", "NAME"}, {"user.email", "email@domain.to"}}; - vlt.init(git_cfg); - ensure("Vault is created", os::path::isDir(vault_dir)); - ensure("Vault exists", vlt.exists()); - ensure("Vault is invalid", !vlt.isInvalid()); + vlt->init(git_cfg); + ensure(S_("No vault dir", vault_dir), os::path::isDir(vault_dir)); + ensure(S_("Vault doesn't exists", vault_dir), vlt->exists()); + ensure(S_("Vault is invalid", vault_dir), !vlt->isInvalid()); } -void register_unit(const QString &name, bool is_global) -{ - QVariantMap data = {{"action", "register"}, - {"data", "name=" + name + ",group=group1," - + "script=./" + name + "_vault_test"}}; - if (is_global) { - data["global"] = true; - } else { - data["vault"] = vault_dir; - } - return vault::Vault::execute(data); -}; - template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_init); vault_init(); on_exit(); } @@ -109,8 +107,8 @@ void object::test() template<> template<> void object::test() { - auto on_exit = setup(); - register_unit("unit1", true); + auto on_exit = setup(tid_config_global); + register_unit(vault_dir, "unit1", true); QString unit1_fname = os::path::join(global_mod_dir, "unit1.json"); ensure("unit 1 global config", os::path::isFile(unit1_fname)); @@ -120,7 +118,7 @@ void object::test() mod_count += units.size(); ensure("One unit/member", mod_count == 1); - register_unit("unit2", true); + register_unit(vault_dir, "unit2", true); units = vault::config::global()->units(); mod_count = 0; QString unit2_fname = os::path::join(global_mod_dir, "unit2.json"); @@ -142,17 +140,17 @@ void object::test() template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_config_local); vault_init(); - register_unit("unit1", false); + register_unit(vault_dir, "unit1", false); QString config_dir = vault::config::units_path(vault_dir); vault::config::Config config(config_dir); ensure("unit1 config file", os::path::isFile(config.path("unit1"))); - QMap units = vlt.config().units(); + QMap units = vlt->config().units(); ensure("no unit1 in vault config", units.contains("unit1")); vault::Vault::execute({{"action", "unregister"}, {"vault", vault_dir}, {"unit", "unit1"}}); - units = vlt.config().units(); + units = vlt->config().units(); ensure("no unit1 in vault config", !units.contains("unit1")); on_exit(); }; @@ -160,21 +158,21 @@ void object::test() template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_config_update); os::rmtree(home); os::mkdir(home); vault_init(); - register_unit("unit1", true); + register_unit(vault_dir, "unit1", true); QMap units = vault::config::global()->units(); ensure("no unit1 in global config", units.contains("unit1")); - register_unit("unit2", false); - vault::config::Vault config = vlt.config(); + register_unit(vault_dir, "unit2", false); + vault::config::Vault config = vlt->config(); units = config.units(); ensure("no unit2 in vault config", units.contains("unit2")); config.update(vault::config::global()->units()); - units = vlt.config().units(); + units = vlt->config().units(); ensure("no unit1 in vault config", units.contains("unit1")); ensure("unit2 should be removed from vault config", !units.contains("unit2")); on_exit(); @@ -183,7 +181,7 @@ void object::test() void do_backup() { bool is_started = false, is_failed = false; - vlt.backup(home, {}, "", [&](const QString &, const QString &status) { + vlt->backup(home, {}, "", [&](const QString &, const QString &status) { if (status == "fail") is_failed = true; else if (status == "begin") @@ -196,8 +194,8 @@ void do_backup() void do_restore() { bool is_started = false, is_failed = false; - ensure("no snapshot", !vlt.snapshots().isEmpty()); - vlt.restore(vlt.snapshots().last(), home, {}, [&](const QString &, const QString &status) { + ensure("no snapshot", !vlt->snapshots().isEmpty()); + vlt->restore(vlt->snapshots().last(), home, {}, [&](const QString &, const QString &status) { if (status == "fail") is_failed = true; else if (status == "begin") @@ -210,37 +208,41 @@ void do_restore() template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_simple_blobs); os::rmtree(home); os::mkdir(home); vault_init(); - register_unit("unit1", false); - QMap units = vlt.config().units(); + register_unit(vault_dir, "unit1", false); + QMap units = vlt->config().units(); ensure("no unit1 in vault config", units.contains("unit1")); - QString unit1_dir = os::path::join(home, "unit1"); - os::mkdir(unit1_dir); - QString unit1_blob = os::path::join(unit1_dir, "blob1"); - os::write_file(unit1_blob, "1\n2\n3\n"); - ensure("unit1 is prepared", os::path::isDir(unit1_dir)); - ensure("unit1 blob is prepared", os::path::isFile(unit1_blob)); + auto unit1_dir = str(get(context, "unit1_dir")); + mktree(unit1_tree, unit1_dir); + auto ftree_git_before_export = get_ftree(unit1_dir); - ensure("No snapshots yet", vlt.snapshots().length() == 0); + ensure("No snapshots yet", vlt->snapshots().length() == 0); do_backup(); - ensure("Added 1 snapshot", vlt.snapshots().length() == 1); - ensure("unit1 is still here", os::path::isDir(unit1_dir)); - ensure("unit1 blob is still here", os::path::isFile(unit1_blob)); - vault::Vault::UnitPath unit1_vault = vlt.unitPath("unit1"); - QString unit1_vault_path = QFileInfo(unit1_vault.bin).absoluteFilePath(); - ensure("unit1 is in the vault", os::path::isDir(unit1_vault_path)); - QString unit1_vault_blob = os::path::join(unit1_vault_path, "unit1", "blob1"); - ensure("unit1 blob1 is in the vault", os::path::exists(unit1_vault_blob)); - ensure("unit1 blob1 is symlink", os::path::isSymLink(unit1_vault_blob)); - - os::rm(unit1_blob); - ensure("unit1 blob is still here", !os::path::isFile(unit1_blob)); + ensure("Added 1 snapshot", vlt->snapshots().length() == 1); + auto ftree_git_after_export = get_ftree(unit1_dir); + ensure_trees_equal("Src is modified?" + , ftree_git_before_export + , get_ftree(unit1_dir)); + + vault::Vault::UnitPath unit1_vault = vlt->unitPath("unit1"); + QString unit1_vault_path = os::path::canonical(unit1_vault.bin); + ensure(S_("dir is not created", unit1_vault_path) + , os::path::isDir(unit1_vault_path)); + QString unit1_vault_blob = os::path::join(unit1_vault_path, "unit1" + , "binaries", "b1"); + ensure(S_("should be symlink", unit1_vault_blob) + , os::path::isSymLink(unit1_vault_blob)); + + os::rmtree(unit1_dir); + ensure(AT, !os::path::exists(unit1_dir)); do_restore(); - ensure("unit1 blob not restored", os::path::isFile(unit1_blob)); + ensure_trees_equal("Src is not restored?" + , ftree_git_before_export + , get_ftree(unit1_dir)); on_exit(); } @@ -248,40 +250,40 @@ void object::test() template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_clear); os::rmtree(home); // valid vault os::mkdir(home); vault_init(); - ensure("No vault before", os::path::exists(vlt.root())); - ensure("W/o params do nothing", !vlt.clear(QVariantMap())); - ensure("Vault should not be removed", os::path::exists(vlt.root())); - ensure("Should destroy valid valut", vlt.clear({{"destroy", true}})); - ensure("Vault should be removed", !os::path::exists(vlt.root())); + ensure("No vault before", os::path::exists(vlt->root())); + ensure("W/o params do nothing", !vlt->clear(QVariantMap())); + ensure("Vault should not be removed", os::path::exists(vlt->root())); + ensure("Should destroy valid valut", vlt->clear({{"destroy", true}})); + ensure("Vault should be removed", !os::path::exists(vlt->root())); // invalid vault ensure(os::mkdir(vault_dir)); - ensure("Should not destroy invalid vault", !vlt.clear({{"destroy", true}})); - ensure("Invalid vault should not be removed", os::path::exists(vlt.root())); - ensure("Should destroy invalid vault", vlt.clear({{"destroy", true}, {"clear_invalid", true}})); - ensure("Invalid vault should be removed", !os::path::exists(vlt.root())); + ensure("Should not destroy invalid vault", !vlt->clear({{"destroy", true}})); + ensure("Invalid vault should not be removed", os::path::exists(vlt->root())); + ensure("Should destroy invalid vault", vlt->clear({{"destroy", true}, {"clear_invalid", true}})); + ensure("Invalid vault should be removed", !os::path::exists(vlt->root())); // vault with snapshots os::mkdir(home); vault_init(); - register_unit("unit1", false); + register_unit(vault_dir, "unit1", false); QString unit1_dir = os::path::join(home, "unit1"); os::mkdir(unit1_dir); QString unit1_blob = os::path::join(unit1_dir, "blob1"); os::write_file(unit1_blob, "1\n2\n3\n"); - ensure("No snapshots yet", vlt.snapshots().length() == 0); + ensure("No snapshots yet", vlt->snapshots().length() == 0); do_backup(); - ensure("Added 1 snapshot", vlt.snapshots().length() == 1); - ensure("Should not destroy vault with snapshots", !vlt.clear({{"destroy", true}})); - ensure("Should destroy vault with snapshots", vlt.clear({{"destroy", true}, {"ignore_snapshots", true}})); - ensure("Vault should be removed", !os::path::exists(vlt.root())); + ensure("Added 1 snapshot", vlt->snapshots().length() == 1); + ensure("Should not destroy vault with snapshots", !vlt->clear({{"destroy", true}})); + ensure("Should destroy vault with snapshots", vlt->clear({{"destroy", true}, {"ignore_snapshots", true}})); + ensure("Vault should be removed", !os::path::exists(vlt->root())); on_exit(); } @@ -290,12 +292,12 @@ void object::test() template<> template<> void object::test() { - auto on_exit = setup(); + auto on_exit = setup(tid_cli_backup_restore_several_units); os::rmtree(home); os::mkdir(home); vault_init(); - register_unit("unit1", false); - register_unit("unit2", false); + register_unit(vault_dir, "unit1", false); + register_unit(vault_dir, "unit2", false); vault::Vault::execute({{"action", "export"} , {"vault", vault_dir} , {"home", home} diff --git a/tests/vault_context.hpp b/tests/vault_context.hpp index d783c3e..4e454b5 100644 --- a/tests/vault_context.hpp +++ b/tests/vault_context.hpp @@ -1,6 +1,8 @@ #ifndef _VAULT_TESTS_VAULT_CONTEXT_HPP_ #define _VAULT_TESTS_VAULT_CONTEXT_HPP_ +#include "tests_common.hpp" + #include #include @@ -8,8 +10,14 @@ #include +namespace os = qtaround::os; +namespace error = qtaround::error; +namespace util = qtaround::util; + namespace { +using qtaround::subprocess::Process; + QSet get_ftree(QString const &root) { Process ps; @@ -19,6 +27,20 @@ QSet get_ftree(QString const &root) return QSet::fromList(ftree); } +void ensure_trees_equal(QString const &msg + , QSet const &before + , QSet const &after) +{ + using tut::ensure_eq; + auto before_wo_after = before - after; + auto after_wo_before = after - before; + // compare to see difference on failure + ensure_eq(S_(msg + ": something is appeared") + , after_wo_before, QSet()); + ensure_eq(S_(msg, ": something was removed") + , before_wo_after, QSet()); +} + QVariant mktree(QVariantMap const &tree, QString const &root) { using tut::ensure; @@ -44,7 +66,7 @@ QVariant mktree(QVariantMap const &tree, QString const &root) return util::visit(fn, tree, root); } -const QVariantMap context = []() +QVariantMap initContext(QString const &home_subdir = "") { QVariantMap context; auto home = os::environ("VAULT_TEST_TMP_DIR"); @@ -52,14 +74,22 @@ const QVariantMap context = []() home = os::mkTemp({{"dir", true}}); if (home.isEmpty()) - error::raise({{"msg", "Empty home path"}}); + error::raise({{"msg", "Empty tests home path"}}); + + if (home == ".." || home == "." || home == os::home()) + error::raise({{"msg", "Can't use directory"}, {"dir", home }}); if (!(os::path::isDir(home) || os::mkdir(home, {{"parent", true}}))) error::raise({{"msg", "Can't create tmp dir"}, {"dir", home}}); + if (!home_subdir.isEmpty()) + home = os::path::join(home, home_subdir); + auto config_dir = os::environ("VAULT_GLOBAL_CONFIG_DIR"); + // global config_dir should be set from environment, it will be + // used instead of standard global config dir if (config_dir.isEmpty()) - config_dir = os::path::join(home, "config"); + error::raise({{"msg", "Need own global config dir for testing"}}); context = { {"home", home} @@ -75,13 +105,27 @@ const QVariantMap context = []() {"data", os::path::join("unit2", "unit2_data")}})}})} }; return context; -}(); +} + +QVariantMap context = initContext(); + +void reinitContext(QString const &home_subdir) +{ + context = initContext(home_subdir); +}; const QVariantMap unit1_tree = { {"data", map({{"f1", "data1"}})}, {"binaries", map({{"b1", "bin data"}, {"b2", "bin data 2"}})} }; +const QVariantMap unit2_tree = { + {"unit2_data", map({{"f2", "data2"}, {"f3", "data3"}})}, + {"unit2_binaries", map({{"b1", "bin data"}, {"b2", "bin data 2"}})} +}; + } +int register_unit(QString const &vault_dir, const QString &name, bool is_global); + #endif // _VAULT_TESTS_VAULT_CONTEXT_HPP_