unit tests: improve

and add a new one for the indexer
This commit is contained in:
Dirk-Jan C. Binnema 2023-09-12 19:30:18 +03:00
parent 805c5aa287
commit 2f5602b938
14 changed files with 149 additions and 123 deletions

View File

@ -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))

View File

@ -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,

View File

@ -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<Id::RootMaildir>("/home/djcb/Maildir");
auto res = conf_db.set<Id::RootMaildir>("/home/djcb/Maildir");
assert_valid_result(res);
const auto rmd = conf_db.get<Id::RootMaildir>();
assert_equal(rmd, "/home/djcb/Maildir");
}

View File

@ -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*/

View File

@ -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<bool> running{}; /**< Is an index operation in progress? */
std::atomic<size_t> checked{}; /**< Number of messages checked for changes */
std::atomic<size_t> updated{}; /**< Number of messages (re)parsed/added/updated */

View File

@ -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<void>
@ -251,6 +244,7 @@ Mu::maildir_clear_links(const std::string& path)
return Ok();
}
/* LCOV_EXCL_START*/
static Mu::Result<void>
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<void>
@ -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 */

View File

@ -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<TestCase> cases = {

View File

@ -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*/

View File

@ -1,4 +1,4 @@
## Copyright (C) 2021 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
## Copyright (C) 2021-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
##
## 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

View File

@ -1,69 +0,0 @@
/*
** Copyright (C) 2020 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 <vector>
#include <glib.h>
#include <iostream>
#include <sstream>
#include <unistd.h>
#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;
}

View File

@ -45,7 +45,7 @@ static Store
make_test_store(const std::string& test_path, const TestMap& test_map,
Option<const Config&> 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();
}

View File

@ -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);
}

0
testdata/testdir2/bar/.noupdate vendored Normal file
View File

16
testdata/testdir2/bar/cur/mail7 vendored Normal file
View File

@ -0,0 +1,16 @@
Date: Mon, 11 Sep 2023 19:57:25 -0400
From: "Tommy" <tommy@example.com>
Subject: Hide and seek
To: "Andreas" <andy@example.com>
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!