From 2f5602b93824d708d603376c47da391b7f2b106f Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Tue, 12 Sep 2023 19:30:18 +0300 Subject: [PATCH] unit tests: improve and add a new one for the indexer --- guile/tests/test-mu-guile.scm | 8 +-- lib/meson.build | 7 +++ lib/mu-config.cc | 6 ++- lib/mu-indexer.cc | 84 ++++++++++++++++++++++++++++++++ lib/mu-indexer.hh | 8 +-- lib/mu-maildir.cc | 19 ++++---- lib/mu-query-xapianizer.cc | 2 + lib/mu-scanner.cc | 31 ++++-------- lib/tests/meson.build | 2 +- lib/tests/test-indexer.cc | 69 -------------------------- lib/tests/test-mu-store-query.cc | 14 +++--- mu/mu-cmd-find.cc | 6 +-- testdata/testdir2/bar/.noupdate | 0 testdata/testdir2/bar/cur/mail7 | 16 ++++++ 14 files changed, 149 insertions(+), 123 deletions(-) delete mode 100644 lib/tests/test-indexer.cc create mode 100644 testdata/testdir2/bar/.noupdate create mode 100644 testdata/testdir2/bar/cur/mail7 diff --git a/guile/tests/test-mu-guile.scm b/guile/tests/test-mu-guile.scm index d4d37407..afa4f48c 100755 --- a/guile/tests/test-mu-guile.scm +++ b/guile/tests/test-mu-guile.scm @@ -50,8 +50,8 @@ exec guile -e main -s $0 $@ (n-results-or-exit "file:custer.*" 1) (n-results-or-exit "j:sit*" 1) (n-results-or-exit "mime:image/jpeg" 1) - (n-results-or-exit "mime:text/plain" 13) - (n-results-or-exit "y:text*" 13) + (n-results-or-exit "mime:text/plain" 14) + (n-results-or-exit "y:text*" 14) (n-results-or-exit "y:image*" 1) (n-results-or-exit "mime:message/rfc822" 2)) @@ -97,8 +97,8 @@ exec guile -e main -s $0 $@ (define (test-stats) "Test statistical functions." ;; average - (num-equal-or-exit (mu:average mu:size) 82152/13) - (num-equal-or-exit (floor (mu:stddev mu:size)) 13020.0) + (num-equal-or-exit (mu:average mu:size) 82601/14) + (num-equal-or-exit (floor (mu:stddev mu:size)) 12637.0) (num-equal-or-exit (mu:max mu:size) 46308) (num-equal-or-exit (mu:min mu:size) 111)) diff --git a/lib/meson.build b/lib/meson.build index 66fd0f56..857f8a69 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -143,6 +143,13 @@ test('test-query-xapianizer', dependencies: [lib_mu_dep])) +test('test-indexer', + executable('test-indexer', 'mu-indexer.cc', + install: false, + cpp_args: ['-DBUILD_TESTS'], + dependencies: [glib_dep, config_h_dep, + lib_mu_dep])) + test('test-scanner', executable('test-scanner', 'mu-scanner.cc', install: false, diff --git a/lib/mu-config.cc b/lib/mu-config.cc index 61ed54fa..4f310c2d 100644 --- a/lib/mu-config.cc +++ b/lib/mu-config.cc @@ -61,6 +61,8 @@ test_basic() MemDb db; Config conf_db{db}; + g_assert_false(conf_db.read_only()); + using Id = Config::Id; { @@ -69,7 +71,9 @@ test_basic() } { - conf_db.set("/home/djcb/Maildir"); + auto res = conf_db.set("/home/djcb/Maildir"); + assert_valid_result(res); + const auto rmd = conf_db.get(); assert_equal(rmd, "/home/djcb/Maildir"); } diff --git a/lib/mu-indexer.cc b/lib/mu-indexer.cc index 6656f82b..9ec5d4b0 100644 --- a/lib/mu-indexer.cc +++ b/lib/mu-indexer.cc @@ -471,3 +471,87 @@ Indexer::completed() const { return priv_->completed_; } + + +#if BUILD_TESTS +#include "mu-test-utils.hh" + +static void +test_index_basic() +{ + allow_warnings(); + + TempDir tdir; + auto store = Store::make_new(tdir.path(), MU_TESTMAILDIR2); + assert_valid_result(store); + g_assert_true(store->empty()); + + Indexer& idx{store->indexer()}; + + g_assert_false(idx.is_running()); + g_assert_true(idx.stop()); + g_assert_cmpuint(idx.completed(),==, 0); + + const auto& prog{idx.progress()}; + g_assert_false(prog.running); + g_assert_cmpuint(prog.checked,==, 0); + g_assert_cmpuint(prog.updated,==, 0); + g_assert_cmpuint(prog.removed,==, 0); + + Indexer::Config conf{}; + conf.ignore_noupdate = true; + + { + const auto start{time({})}; + g_assert_true(idx.start(conf)); + while (idx.is_running()) + g_usleep(10000); + + g_assert_false(idx.is_running()); + g_assert_true(idx.stop()); + + g_assert_cmpuint(idx.completed() - start, <, 5); + + g_assert_false(prog.running); + g_assert_cmpuint(prog.checked,==, 14); + g_assert_cmpuint(prog.updated,==, 14); + g_assert_cmpuint(prog.removed,==, 0); + + g_assert_cmpuint(store->size(),==,14); + } + + conf.lazy_check = true; + conf.max_threads = 1; + conf.ignore_noupdate = false; + + { + const auto start{time({})}; + g_assert_true(idx.start(conf)); + while (idx.is_running()) + g_usleep(10000); + + g_assert_false(idx.is_running()); + g_assert_true(idx.stop()); + + g_assert_cmpuint(idx.completed() - start, <, 3); + + g_assert_false(prog.running); + g_assert_cmpuint(prog.checked,==, 0); + g_assert_cmpuint(prog.updated,==, 0); + g_assert_cmpuint(prog.removed,==, 0); + + g_assert_cmpuint(store->size(),==, 14); + } +} + +int +main(int argc, char* argv[]) +{ + mu_test_init(&argc, &argv); + + g_test_add_func("/index/basic", test_index_basic); + + return g_test_run(); + +} +#endif /*BUILD_TESTS*/ diff --git a/lib/mu-indexer.hh b/lib/mu-indexer.hh index da7dad09..d65f3bcc 100644 --- a/lib/mu-indexer.hh +++ b/lib/mu-indexer.hh @@ -74,9 +74,7 @@ public: /** * Stop indexing. If not indexing, do nothing. * - * - * @return true if we stopped indexing, or indexing was not underway. - * False otherwise. + * @return true if we stopped indexing, or indexing was not underway; false otherwise. */ bool stop(); @@ -89,12 +87,10 @@ public: // Object describing current progress struct Progress { - void reset() - { + void reset() { running = false; checked = updated = removed = 0; } - std::atomic running{}; /**< Is an index operation in progress? */ std::atomic checked{}; /**< Number of messages checked for changes */ std::atomic updated{}; /**< Number of messages (re)parsed/added/updated */ diff --git a/lib/mu-maildir.cc b/lib/mu-maildir.cc index ad9f89b4..68685c52 100644 --- a/lib/mu-maildir.cc +++ b/lib/mu-maildir.cc @@ -161,18 +161,11 @@ get_target_fullpath(const std::string& src, const std::string& targetpath, * including a hash of the srcname in the targetname. This helps if * there are copies of a message (which all have the same basename) */ - std::string fulltargetpath; if (unique_names) - fulltargetpath = join_paths(targetpath, - in_cur ? "cur" : "new", - mu_format("{:08x}-{}", - g_str_hash(src.c_str()), - srcfile)); + return join_paths(targetpath, in_cur ? "cur" : "new", + mu_format("{:08x}-{}", g_str_hash(src.c_str()), srcfile)); else - fulltargetpath = join_paths(targetpath, - in_cur ? "cur" : "new", - srcfile.c_str()); - return fulltargetpath; + return join_paths(targetpath, in_cur ? "cur" : "new", srcfile.c_str()); } Result @@ -251,6 +244,7 @@ Mu::maildir_clear_links(const std::string& path) return Ok(); } +/* LCOV_EXCL_START*/ static Mu::Result msg_move_verify(const std::string& src, const std::string& dst) { @@ -270,7 +264,11 @@ msg_move_verify(const std::string& src, const std::string& dst) return Ok(); } +/* LCOV_EXCL_STOP*/ +/* LCOV_EXCL_START*/ +// don't use this right now, since it gives as (false alarm) +// valgrind warning in tests /* use GIO to move files; this is slower than rename() so only use * this when needed: when moving across filesystems */ G_GNUC_UNUSED static Mu::Result @@ -291,6 +289,7 @@ msg_move_g_file(const std::string& src, const std::string& dst) else return Err(Error::Code::File, &err, "error moving {} -> {}", src, dst); } +/* LCOV_EXCL_STOPT*/ /* use mv to move files; this is slower than rename() so only use this when * needed: when moving across filesystems */ diff --git a/lib/mu-query-xapianizer.cc b/lib/mu-query-xapianizer.cc index d964bb2e..e63c83a0 100644 --- a/lib/mu-query-xapianizer.cc +++ b/lib/mu-query-xapianizer.cc @@ -431,6 +431,7 @@ test_xapian() // to be the same between versions auto&& zz{make_xapian_query(store, R"(subject:"hello world")")}; assert_valid_result(zz); + /* LCOV_EXCL_START*/ if (zz->get_description() != R"(Query((Shello PHRASE 2 Sworld)))") { if (mu_test_mu_hacker()) { // in the mu hacker case, we want to be warned if Xapian changed. @@ -441,6 +442,7 @@ test_xapian() return; } } + /* LCOV_EXCL_STOP*/ std::vector cases = { diff --git a/lib/mu-scanner.cc b/lib/mu-scanner.cc index f9dfac9b..89cfb6b7 100644 --- a/lib/mu-scanner.cc +++ b/lib/mu-scanner.cc @@ -103,20 +103,16 @@ ignore_dentry(const dentry_t& dentry) (d_name[2] == '\0' && d_name[0] == '.' && d_name[1] == '.')) return true; - if (g_strcmp0(d_name, "tmp") == 0) - return true; + if (d_name[0] != 't' && d_name[0] != 'h' && d_name[0] != '.') + return false; /* don't ignore */ - if (d_name[0] == '.') { - if (d_name[1] == '#') /* emacs? */ - return true; - if (g_strcmp0(d_name + 1, "nnmaildir") == 0) /* gnus? */ - return true; - if (g_strcmp0(d_name + 1, "notmuch") == 0) /* notmuch? */ - return true; - } + if (::strcmp(d_name, "tmp") == 0 || ::strcmp(d_name, "hcache.db") == 0) + return true; // ignore - if (g_strcmp0(d_name, "hcache.db") == 0) /* mutt cache? */ - return true; + if (d_name[0] == '.') + for (auto dname : { "nnmaildir", "notmuch", "noindex", "noupdate"}) + if (::strcmp(d_name + 1, dname) == 0) + return true; return false; /* don't ignore */ } @@ -373,20 +369,13 @@ test_count_maildirs() int main(int argc, char* argv[]) -try { - g_test_init(&argc, &argv, NULL); +{ + mu_test_init(&argc, &argv); g_test_add_func("/index/scan-maildirs", test_scan_maildirs); g_test_add_func("/index/count-maildirs", test_count_maildirs); return g_test_run(); - -} catch (const std::runtime_error& re) { - mu_printerrln("caught runtime error: {}", re.what()); - return 1; -} catch (...) { - mu_printerrln("caught exception"); - return 1; } #endif /*BUILD_TESTS*/ diff --git a/lib/tests/meson.build b/lib/tests/meson.build index 5427fbb3..5d21ea1c 100644 --- a/lib/tests/meson.build +++ b/lib/tests/meson.build @@ -1,4 +1,4 @@ -## Copyright (C) 2021 Dirk-Jan C. Binnema +## Copyright (C) 2021-2023 Dirk-Jan C. Binnema ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by diff --git a/lib/tests/test-indexer.cc b/lib/tests/test-indexer.cc deleted file mode 100644 index 32e9ea39..00000000 --- a/lib/tests/test-indexer.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* -** Copyright (C) 2020 Dirk-Jan C. Binnema -** -** This program is free software; you can redistribute it and/or modify it -** under the terms of the GNU General Public License as published by the -** Free Software Foundation; either version 3, or (at your option) any -** later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software Foundation, -** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -** -*/ - -#include -#include - -#include -#include -#include - -#include "mu-indexer.hh" -#include "utils/mu-utils.hh" -#include "test-mu-common.h" - -using namespace Mu; - -static void -test_index_maildir() -{ - allow_warnings(); - - Store store{test_mu_common_get_random_tmpdir(), std::string{MU_TESTMAILDIR}}; - Indexer idx{Indexer::Config{}, store}; - - g_assert_true(idx.start()); - while (idx.is_running()) { - sleep(1); - } - - g_print("again!\n"); - - g_assert_true(idx.start()); - while (idx.is_running()) { - sleep(1); - } -} - -int -main(int argc, char* argv[]) -try { - g_test_init(&argc, &argv, NULL); - - g_test_add_func("/indexer/index-maildir", test_index_maildir); - - return g_test_run(); - -} catch (const std::runtime_error& re) { - std::cerr << re.what() << "\n"; - return 1; -} catch (...) { - std::cerr << "caught exception\n"; - return 1; -} diff --git a/lib/tests/test-mu-store-query.cc b/lib/tests/test-mu-store-query.cc index 3052b03b..6148c1d2 100644 --- a/lib/tests/test-mu-store-query.cc +++ b/lib/tests/test-mu-store-query.cc @@ -45,7 +45,7 @@ static Store make_test_store(const std::string& test_path, const TestMap& test_map, Option conf={}) { - std::string maildir = test_path + "/Maildir/"; + const auto maildir{join_paths(test_path, "/Maildir/")}; // note the trailing '/' g_test_bug("2513"); @@ -819,7 +819,7 @@ html static void -test_cjk() +test_ngrams() { g_test_bug("2167"); @@ -882,9 +882,8 @@ main(int argc, char* argv[]) { mu_test_init(&argc, &argv); - //_test_add_func("/store/query/cjk", test_cjk); - - g_test_add_func("/store/query/simple", test_simple); + g_test_add_func("/store/query/simple", + test_simple); g_test_add_func("/store/query/spam-address-components", test_spam_address_components); g_test_add_func("/store/query/dups-related", @@ -905,9 +904,8 @@ main(int argc, char* argv[]) test_related_dup_threaded); g_test_add_func("/store/query/html", test_html); - - g_test_add_func("/store/query/cjk-once-more", test_cjk); - + g_test_add_func("/store/query/ngrams", + test_ngrams); return g_test_run(); } diff --git a/mu/mu-cmd-find.cc b/mu/mu-cmd-find.cc index 33792958..f21ff6e5 100644 --- a/mu/mu-cmd-find.cc +++ b/mu/mu-cmd-find.cc @@ -558,7 +558,7 @@ search_func(const std::string& expr, size_t expected) static void test_mu_find_empty_query(void) { - search("\"\"", 13); + search("\"\"", 14); } static void @@ -601,8 +601,8 @@ static void test_mu_find_mime(void) { search("mime:image/jpeg", 1); - search("mime:text/plain", 13); - search("y:text*", 13); + search("mime:text/plain", 14); + search("y:text*", 14); search("y:image*", 1); search("mime:message/rfc822", 2); } diff --git a/testdata/testdir2/bar/.noupdate b/testdata/testdir2/bar/.noupdate new file mode 100644 index 00000000..e69de29b diff --git a/testdata/testdir2/bar/cur/mail7 b/testdata/testdir2/bar/cur/mail7 new file mode 100644 index 00000000..48660f35 --- /dev/null +++ b/testdata/testdir2/bar/cur/mail7 @@ -0,0 +1,16 @@ +Date: Mon, 11 Sep 2023 19:57:25 -0400 +From: "Tommy" +Subject: Hide and seek +To: "Andreas" +Message-id: <3BE9E65sdfklsajdfl3E7A1A20D852173@msg.id> +MIME-version: 1.0 + +Behind the polished barrier +The pending storm draws near +Although it's an inferno +You can not step back for your fears +Hurry son I need to rest +finish the puzzle you do it best +I'll do what I can +But I am telling you +It can't be done without you!