mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-24 20:08:10 +01:00
test: Test thread linking in all possible delivery orders
These tests deliver all possible (single-root) four-message threads in all possible orders and check that notmuch successfully links them into threads. These tests supersede and replace the previous and much less thorough "T260-thread-order" tests. There are two variants of the test: one delivers messages that reference only their immediate parent and the other delivers messages that reference all of their parents. The latter test is currently known-broken.
This commit is contained in:
parent
de37f21e5b
commit
c2bbe9eb6c
2 changed files with 98 additions and 21 deletions
|
@ -2,31 +2,75 @@
|
||||||
test_description="threading when messages received out of order"
|
test_description="threading when messages received out of order"
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
test_begin_subtest "Adding initial child message"
|
# Generate all single-root four message thread structures. We'll use
|
||||||
generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
|
# this for multiple tests below.
|
||||||
output=$(NOTMUCH_NEW)
|
THREADS=$(python ${TEST_DIRECTORY}/gen-threads.py 4)
|
||||||
test_expect_equal "$output" "Added 1 new message to the database."
|
nthreads=$(wc -l <<< "$THREADS")
|
||||||
|
|
||||||
test_begin_subtest "Searching returns the message"
|
test_begin_subtest "Messages with one parent get linked in all delivery orders"
|
||||||
output=$(notmuch search foo | notmuch_search_sanitize)
|
# In the first variant, this delivers messages that reference only
|
||||||
test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; brokenthreadtest (inbox unread)"
|
# their immediate parent. Hence, we should only expect threads to be
|
||||||
|
# fully joined at the end.
|
||||||
|
for ((n = 0; n < 4; n++)); do
|
||||||
|
# Deliver the n'th message of every thread
|
||||||
|
thread=0
|
||||||
|
while read -a parents; do
|
||||||
|
parent=${parents[$n]}
|
||||||
|
generate_message \
|
||||||
|
[id]=m$n@t$thread [in-reply-to]="\<m$parent@t$thread\>" \
|
||||||
|
[subject]=p$thread [from]=m$n
|
||||||
|
thread=$((thread + 1))
|
||||||
|
done <<< "$THREADS"
|
||||||
|
notmuch new > /dev/null
|
||||||
|
done
|
||||||
|
output=$(notmuch search --sort=newest-first '*' | notmuch_search_sanitize)
|
||||||
|
expected=$(for ((i = 0; i < $nthreads; i++)); do
|
||||||
|
echo "thread:XXX 2001-01-05 [4/4] m3, m2, m1, m0; p$i (inbox unread)"
|
||||||
|
done)
|
||||||
|
test_expect_equal "$output" "$expected"
|
||||||
|
|
||||||
test_begin_subtest "Adding second child message"
|
test_begin_subtest "Messages with all parents get linked in all delivery orders"
|
||||||
generate_message [body]=foo "[in-reply-to]=\<parent-id\>" [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
|
test_subtest_known_broken
|
||||||
output=$(NOTMUCH_NEW)
|
# Here we do the same thing as the previous test, but each message
|
||||||
test_expect_equal "$output" "Added 1 new message to the database."
|
# references all of its parents. Since every message references the
|
||||||
|
# root of the thread, each thread should always be fully joined. This
|
||||||
|
# is currently broken because of the bug detailed in
|
||||||
|
# id:8738h7kv2q.fsf@qmul.ac.uk.
|
||||||
|
rm ${MAIL_DIR}/*
|
||||||
|
notmuch new > /dev/null
|
||||||
|
output=""
|
||||||
|
expected=""
|
||||||
|
for ((n = 0; n < 4; n++)); do
|
||||||
|
# Deliver the n'th message of every thread
|
||||||
|
thread=0
|
||||||
|
while read -a parents; do
|
||||||
|
references=""
|
||||||
|
parent=${parents[$n]}
|
||||||
|
while [[ $parent != None ]]; do
|
||||||
|
references="<m$parent@t$thread> $references"
|
||||||
|
parent=${parents[$parent]}
|
||||||
|
done
|
||||||
|
|
||||||
test_begin_subtest "Searching returns both messages in one thread"
|
generate_message \
|
||||||
output=$(notmuch search foo | notmuch_search_sanitize)
|
[id]=m$n@t$thread [references]="'$references'" \
|
||||||
test_expect_equal "$output" "thread:XXX 2000-01-01 [2/2] Notmuch Test Suite; brokenthreadtest (inbox unread)"
|
[subject]=p$thread [from]=m$n
|
||||||
|
thread=$((thread + 1))
|
||||||
|
done <<< "$THREADS"
|
||||||
|
notmuch new > /dev/null
|
||||||
|
|
||||||
test_begin_subtest "Adding parent message"
|
output="$output
|
||||||
generate_message [body]=foo [id]=parent-id [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
|
$(notmuch search --sort=newest-first '*' | notmuch_search_sanitize)"
|
||||||
output=$(NOTMUCH_NEW)
|
|
||||||
test_expect_equal "$output" "Added 1 new message to the database."
|
|
||||||
|
|
||||||
test_begin_subtest "Searching returns all three messages in one thread"
|
# Construct expected output
|
||||||
output=$(notmuch search foo | notmuch_search_sanitize)
|
template="thread:XXX 2001-01-05 [$((n+1))/$((n+1))]"
|
||||||
test_expect_equal "$output" "thread:XXX 2000-01-01 [3/3] Notmuch Test Suite; brokenthreadtest (inbox unread)"
|
for ((m = n; m > 0; m--)); do
|
||||||
|
template="$template m$m,"
|
||||||
|
done
|
||||||
|
expected="$expected
|
||||||
|
$(for ((i = 0; i < $nthreads; i++)); do
|
||||||
|
echo "$template m0; p$i (inbox unread)"
|
||||||
|
done)"
|
||||||
|
done
|
||||||
|
test_expect_equal "$output" "$expected"
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
33
test/gen-threads.py
Normal file
33
test/gen-threads.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Generate all possible single-root message thread structures of size
|
||||||
|
# argv[1]. Each output line is a thread structure, where the n'th
|
||||||
|
# field is either a number giving the parent of message n or "None"
|
||||||
|
# for the root.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from itertools import chain, combinations
|
||||||
|
|
||||||
|
def subsets(s):
|
||||||
|
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
|
||||||
|
|
||||||
|
nodes = set(range(int(sys.argv[1])))
|
||||||
|
|
||||||
|
# Queue of (tree, free, to_expand) where tree is a {node: parent}
|
||||||
|
# dictionary, free is a set of unattached nodes, and to_expand is
|
||||||
|
# itself a queue of nodes in the tree that need to be expanded.
|
||||||
|
# The queue starts with all single-node trees.
|
||||||
|
queue = [({root: None}, nodes - {root}, (root,)) for root in nodes]
|
||||||
|
|
||||||
|
# Process queue
|
||||||
|
while queue:
|
||||||
|
tree, free, to_expand = queue.pop()
|
||||||
|
|
||||||
|
if len(to_expand) == 0:
|
||||||
|
# Only print full-sized trees
|
||||||
|
if len(free) == 0:
|
||||||
|
print(" ".join(map(str, [msg[1] for msg in sorted(tree.items())])))
|
||||||
|
else:
|
||||||
|
# Expand node to_expand[0] with each possible set of children
|
||||||
|
for children in subsets(free):
|
||||||
|
ntree = dict(tree, **{child: to_expand[0] for child in children})
|
||||||
|
nfree = free.difference(children)
|
||||||
|
queue.append((ntree, nfree, to_expand[1:] + tuple(children)))
|
Loading…
Reference in a new issue